2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
8 * Copyright (C) 2011 Dylan Smith
9 * Copyright (C) 2011 Michael Mc Donnell
10 * Copyright (C) 2013 Christian Costa
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Lesser General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Lesser General Public License for more details.
22 * You should have received a copy of the GNU Lesser General Public
23 * License along with this library; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #define WIN32_NO_STATUS
29 #define COM_NO_WINDOWS_H
32 #include <wine/port.h>
35 #define NONAMELESSUNION
49 #include "wine/debug.h"
50 #include "wine/unicode.h"
51 #include "wine/list.h"
52 #include "d3dx9_36_private.h"
54 #define fmax(a, b) ((a) > (b) ? (a) : (b))
56 WINE_DEFAULT_DEBUG_CHANNEL(d3dx
);
58 typedef struct ID3DXMeshImpl
60 ID3DXMesh ID3DXMesh_iface
;
67 IDirect3DDevice9
*device
;
68 D3DVERTEXELEMENT9 cached_declaration
[MAX_FVF_DECL_SIZE
];
69 IDirect3DVertexDeclaration9
*vertex_declaration
;
70 UINT vertex_declaration_size
;
72 IDirect3DVertexBuffer9
*vertex_buffer
;
73 IDirect3DIndexBuffer9
*index_buffer
;
75 int attrib_buffer_lock_count
;
76 DWORD attrib_table_size
;
77 D3DXATTRIBUTERANGE
*attrib_table
;
80 const UINT d3dx_decltype_size
[] =
82 /* D3DDECLTYPE_FLOAT1 */ sizeof(FLOAT
),
83 /* D3DDECLTYPE_FLOAT2 */ sizeof(D3DXVECTOR2
),
84 /* D3DDECLTYPE_FLOAT3 */ sizeof(D3DXVECTOR3
),
85 /* D3DDECLTYPE_FLOAT4 */ sizeof(D3DXVECTOR4
),
86 /* D3DDECLTYPE_D3DCOLOR */ sizeof(D3DCOLOR
),
87 /* D3DDECLTYPE_UBYTE4 */ 4 * sizeof(BYTE
),
88 /* D3DDECLTYPE_SHORT2 */ 2 * sizeof(SHORT
),
89 /* D3DDECLTYPE_SHORT4 */ 4 * sizeof(SHORT
),
90 /* D3DDECLTYPE_UBYTE4N */ 4 * sizeof(BYTE
),
91 /* D3DDECLTYPE_SHORT2N */ 2 * sizeof(SHORT
),
92 /* D3DDECLTYPE_SHORT4N */ 4 * sizeof(SHORT
),
93 /* D3DDECLTYPE_USHORT2N */ 2 * sizeof(USHORT
),
94 /* D3DDECLTYPE_USHORT4N */ 4 * sizeof(USHORT
),
95 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
96 /* D3DDECLTYPE_DEC3N */ 4,
97 /* D3DDECLTYPE_FLOAT16_2 */ 2 * sizeof(D3DXFLOAT16
),
98 /* D3DDECLTYPE_FLOAT16_4 */ 4 * sizeof(D3DXFLOAT16
),
101 static inline ID3DXMeshImpl
*impl_from_ID3DXMesh(ID3DXMesh
*iface
)
103 return CONTAINING_RECORD(iface
, ID3DXMeshImpl
, ID3DXMesh_iface
);
106 static HRESULT WINAPI
ID3DXMeshImpl_QueryInterface(ID3DXMesh
*iface
, REFIID riid
, LPVOID
*object
)
108 TRACE("(%p)->(%s, %p)\n", iface
, debugstr_guid(riid
), object
);
110 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
111 IsEqualGUID(riid
, &IID_ID3DXBaseMesh
) ||
112 IsEqualGUID(riid
, &IID_ID3DXMesh
))
114 iface
->lpVtbl
->AddRef(iface
);
119 WARN("Interface %s not found.\n", debugstr_guid(riid
));
121 return E_NOINTERFACE
;
124 static ULONG WINAPI
ID3DXMeshImpl_AddRef(ID3DXMesh
*iface
)
126 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
128 TRACE("(%p)->(): AddRef from %d\n", This
, This
->ref
);
130 return InterlockedIncrement(&This
->ref
);
133 static ULONG WINAPI
ID3DXMeshImpl_Release(ID3DXMesh
*iface
)
135 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
136 ULONG ref
= InterlockedDecrement(&This
->ref
);
138 TRACE("(%p)->(): Release from %d\n", This
, ref
+ 1);
142 IDirect3DIndexBuffer9_Release(This
->index_buffer
);
143 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
144 if (This
->vertex_declaration
)
145 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
146 IDirect3DDevice9_Release(This
->device
);
147 HeapFree(GetProcessHeap(), 0, This
->attrib_buffer
);
148 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
149 HeapFree(GetProcessHeap(), 0, This
);
155 /*** ID3DXBaseMesh ***/
156 static HRESULT WINAPI
ID3DXMeshImpl_DrawSubset(ID3DXMesh
*iface
, DWORD attrib_id
)
158 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
164 TRACE("(%p)->(%u)\n", This
, attrib_id
);
166 if (!This
->vertex_declaration
)
168 WARN("Can't draw a mesh with an invalid vertex declaration.\n");
172 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
174 hr
= IDirect3DDevice9_SetVertexDeclaration(This
->device
, This
->vertex_declaration
);
175 if (FAILED(hr
)) return hr
;
176 hr
= IDirect3DDevice9_SetStreamSource(This
->device
, 0, This
->vertex_buffer
, 0, vertex_size
);
177 if (FAILED(hr
)) return hr
;
178 hr
= IDirect3DDevice9_SetIndices(This
->device
, This
->index_buffer
);
179 if (FAILED(hr
)) return hr
;
181 while (face_end
< This
->numfaces
)
183 for (face_start
= face_end
; face_start
< This
->numfaces
; face_start
++)
185 if (This
->attrib_buffer
[face_start
] == attrib_id
)
188 if (face_start
>= This
->numfaces
)
190 for (face_end
= face_start
+ 1; face_end
< This
->numfaces
; face_end
++)
192 if (This
->attrib_buffer
[face_end
] != attrib_id
)
196 hr
= IDirect3DDevice9_DrawIndexedPrimitive(This
->device
, D3DPT_TRIANGLELIST
,
197 0, 0, This
->numvertices
, face_start
* 3, face_end
- face_start
);
198 if (FAILED(hr
)) return hr
;
204 static DWORD WINAPI
ID3DXMeshImpl_GetNumFaces(ID3DXMesh
*iface
)
206 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
208 TRACE("(%p)\n", This
);
210 return This
->numfaces
;
213 static DWORD WINAPI
ID3DXMeshImpl_GetNumVertices(ID3DXMesh
*iface
)
215 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
217 TRACE("(%p)\n", This
);
219 return This
->numvertices
;
222 static DWORD WINAPI
ID3DXMeshImpl_GetFVF(ID3DXMesh
*iface
)
224 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
226 TRACE("(%p)\n", This
);
231 static void copy_declaration(D3DVERTEXELEMENT9
*dst
, const D3DVERTEXELEMENT9
*src
, UINT num_elem
)
233 memcpy(dst
, src
, num_elem
* sizeof(*src
));
236 static HRESULT WINAPI
ID3DXMeshImpl_GetDeclaration(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
238 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
240 TRACE("(%p)\n", This
);
242 if (declaration
== NULL
) return D3DERR_INVALIDCALL
;
244 copy_declaration(declaration
, This
->cached_declaration
, This
->num_elem
);
249 static DWORD WINAPI
ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh
*iface
)
251 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
253 TRACE("iface (%p)\n", This
);
255 return This
->vertex_declaration_size
;
258 static DWORD WINAPI
ID3DXMeshImpl_GetOptions(ID3DXMesh
*iface
)
260 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
262 TRACE("(%p)\n", This
);
264 return This
->options
;
267 static HRESULT WINAPI
ID3DXMeshImpl_GetDevice(struct ID3DXMesh
*iface
, struct IDirect3DDevice9
**device
)
269 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
271 TRACE("(%p)->(%p)\n", This
, device
);
273 if (device
== NULL
) return D3DERR_INVALIDCALL
;
274 *device
= This
->device
;
275 IDirect3DDevice9_AddRef(This
->device
);
280 static HRESULT WINAPI
ID3DXMeshImpl_CloneMeshFVF(struct ID3DXMesh
*iface
, DWORD options
, DWORD fvf
,
281 struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh
)
283 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
285 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
287 TRACE("(%p)->(%x,%x,%p,%p)\n", This
, options
, fvf
, device
, clone_mesh
);
289 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
290 if (FAILED(hr
)) return hr
;
292 return iface
->lpVtbl
->CloneMesh(iface
, options
, declaration
, device
, clone_mesh
);
295 static FLOAT
scale_clamp_ubyten(FLOAT value
)
297 value
= value
* UCHAR_MAX
;
305 if (value
> UCHAR_MAX
) /* Clamp at 255 */
312 static FLOAT
scale_clamp_shortn(FLOAT value
)
314 value
= value
* SHRT_MAX
;
316 /* The tests show that the range is SHRT_MIN + 1 to SHRT_MAX. */
317 if (value
<= SHRT_MIN
)
321 else if (value
> SHRT_MAX
)
331 static FLOAT
scale_clamp_ushortn(FLOAT value
)
333 value
= value
* USHRT_MAX
;
341 if (value
> USHRT_MAX
) /* Clamp at 65535 */
348 static INT
simple_round(FLOAT value
)
350 int res
= (INT
)(value
+ 0.5f
);
355 static void convert_float4(BYTE
*dst
, CONST D3DXVECTOR4
*src
, D3DDECLTYPE type_dst
)
357 BOOL fixme_once
= FALSE
;
361 case D3DDECLTYPE_FLOAT1
:
363 FLOAT
*dst_ptr
= (FLOAT
*)dst
;
367 case D3DDECLTYPE_FLOAT2
:
369 D3DXVECTOR2
*dst_ptr
= (D3DXVECTOR2
*)dst
;
374 case D3DDECLTYPE_FLOAT3
:
376 D3DXVECTOR3
*dst_ptr
= (D3DXVECTOR3
*)dst
;
382 case D3DDECLTYPE_FLOAT4
:
384 D3DXVECTOR4
*dst_ptr
= (D3DXVECTOR4
*)dst
;
391 case D3DDECLTYPE_D3DCOLOR
:
393 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
394 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
395 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
396 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
399 case D3DDECLTYPE_UBYTE4
:
401 dst
[0] = src
->x
< 0.0f
? 0 : (BYTE
)simple_round(src
->x
);
402 dst
[1] = src
->y
< 0.0f
? 0 : (BYTE
)simple_round(src
->y
);
403 dst
[2] = src
->z
< 0.0f
? 0 : (BYTE
)simple_round(src
->z
);
404 dst
[3] = src
->w
< 0.0f
? 0 : (BYTE
)simple_round(src
->w
);
407 case D3DDECLTYPE_SHORT2
:
409 SHORT
*dst_ptr
= (SHORT
*)dst
;
410 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
411 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
414 case D3DDECLTYPE_SHORT4
:
416 SHORT
*dst_ptr
= (SHORT
*)dst
;
417 dst_ptr
[0] = (SHORT
)simple_round(src
->x
);
418 dst_ptr
[1] = (SHORT
)simple_round(src
->y
);
419 dst_ptr
[2] = (SHORT
)simple_round(src
->z
);
420 dst_ptr
[3] = (SHORT
)simple_round(src
->w
);
423 case D3DDECLTYPE_UBYTE4N
:
425 dst
[0] = (BYTE
)simple_round(scale_clamp_ubyten(src
->x
));
426 dst
[1] = (BYTE
)simple_round(scale_clamp_ubyten(src
->y
));
427 dst
[2] = (BYTE
)simple_round(scale_clamp_ubyten(src
->z
));
428 dst
[3] = (BYTE
)simple_round(scale_clamp_ubyten(src
->w
));
431 case D3DDECLTYPE_SHORT2N
:
433 SHORT
*dst_ptr
= (SHORT
*)dst
;
434 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
435 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
438 case D3DDECLTYPE_SHORT4N
:
440 SHORT
*dst_ptr
= (SHORT
*)dst
;
441 dst_ptr
[0] = (SHORT
)simple_round(scale_clamp_shortn(src
->x
));
442 dst_ptr
[1] = (SHORT
)simple_round(scale_clamp_shortn(src
->y
));
443 dst_ptr
[2] = (SHORT
)simple_round(scale_clamp_shortn(src
->z
));
444 dst_ptr
[3] = (SHORT
)simple_round(scale_clamp_shortn(src
->w
));
447 case D3DDECLTYPE_USHORT2N
:
449 USHORT
*dst_ptr
= (USHORT
*)dst
;
450 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
451 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
454 case D3DDECLTYPE_USHORT4N
:
456 USHORT
*dst_ptr
= (USHORT
*)dst
;
457 dst_ptr
[0] = (USHORT
)simple_round(scale_clamp_ushortn(src
->x
));
458 dst_ptr
[1] = (USHORT
)simple_round(scale_clamp_ushortn(src
->y
));
459 dst_ptr
[2] = (USHORT
)simple_round(scale_clamp_ushortn(src
->z
));
460 dst_ptr
[3] = (USHORT
)simple_round(scale_clamp_ushortn(src
->w
));
463 case D3DDECLTYPE_FLOAT16_2
:
465 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 2);
468 case D3DDECLTYPE_FLOAT16_4
:
470 D3DXFloat32To16Array((D3DXFLOAT16
*)dst
, (FLOAT
*)src
, 4);
475 FIXME("Conversion from D3DDECLTYPE_FLOAT4 to %d not implemented.\n", type_dst
);
480 static void convert_component(BYTE
*dst
, BYTE
*src
, D3DDECLTYPE type_dst
, D3DDECLTYPE type_src
)
482 BOOL fixme_once
= FALSE
;
486 case D3DDECLTYPE_FLOAT1
:
488 FLOAT
*src_ptr
= (FLOAT
*)src
;
489 D3DXVECTOR4 src_float4
= {*src_ptr
, 0.0f
, 0.0f
, 1.0f
};
490 convert_float4(dst
, &src_float4
, type_dst
);
493 case D3DDECLTYPE_FLOAT2
:
495 D3DXVECTOR2
*src_ptr
= (D3DXVECTOR2
*)src
;
496 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, 0.0f
, 1.0f
};
497 convert_float4(dst
, &src_float4
, type_dst
);
500 case D3DDECLTYPE_FLOAT3
:
502 D3DXVECTOR3
*src_ptr
= (D3DXVECTOR3
*)src
;
503 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, 1.0f
};
504 convert_float4(dst
, &src_float4
, type_dst
);
507 case D3DDECLTYPE_FLOAT4
:
509 D3DXVECTOR4
*src_ptr
= (D3DXVECTOR4
*)src
;
510 D3DXVECTOR4 src_float4
= {src_ptr
->x
, src_ptr
->y
, src_ptr
->z
, src_ptr
->w
};
511 convert_float4(dst
, &src_float4
, type_dst
);
514 case D3DDECLTYPE_D3DCOLOR
:
516 D3DXVECTOR4 src_float4
=
518 (FLOAT
)src
[2]/UCHAR_MAX
,
519 (FLOAT
)src
[1]/UCHAR_MAX
,
520 (FLOAT
)src
[0]/UCHAR_MAX
,
521 (FLOAT
)src
[3]/UCHAR_MAX
523 convert_float4(dst
, &src_float4
, type_dst
);
526 case D3DDECLTYPE_UBYTE4
:
528 D3DXVECTOR4 src_float4
= {src
[0], src
[1], src
[2], src
[3]};
529 convert_float4(dst
, &src_float4
, type_dst
);
532 case D3DDECLTYPE_SHORT2
:
534 SHORT
*src_ptr
= (SHORT
*)src
;
535 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], 0.0f
, 1.0f
};
536 convert_float4(dst
, &src_float4
, type_dst
);
539 case D3DDECLTYPE_SHORT4
:
541 SHORT
*src_ptr
= (SHORT
*)src
;
542 D3DXVECTOR4 src_float4
= {src_ptr
[0], src_ptr
[1], src_ptr
[2], src_ptr
[3]};
543 convert_float4(dst
, &src_float4
, type_dst
);
546 case D3DDECLTYPE_UBYTE4N
:
548 D3DXVECTOR4 src_float4
=
550 (FLOAT
)src
[0]/UCHAR_MAX
,
551 (FLOAT
)src
[1]/UCHAR_MAX
,
552 (FLOAT
)src
[2]/UCHAR_MAX
,
553 (FLOAT
)src
[3]/UCHAR_MAX
555 convert_float4(dst
, &src_float4
, type_dst
);
558 case D3DDECLTYPE_SHORT2N
:
560 SHORT
*src_ptr
= (SHORT
*)src
;
561 D3DXVECTOR4 src_float4
= {(FLOAT
)src_ptr
[0]/SHRT_MAX
, (FLOAT
)src_ptr
[1]/SHRT_MAX
, 0.0f
, 1.0f
};
562 convert_float4(dst
, &src_float4
, type_dst
);
565 case D3DDECLTYPE_SHORT4N
:
567 SHORT
*src_ptr
= (SHORT
*)src
;
568 D3DXVECTOR4 src_float4
=
570 (FLOAT
)src_ptr
[0]/SHRT_MAX
,
571 (FLOAT
)src_ptr
[1]/SHRT_MAX
,
572 (FLOAT
)src_ptr
[2]/SHRT_MAX
,
573 (FLOAT
)src_ptr
[3]/SHRT_MAX
575 convert_float4(dst
, &src_float4
, type_dst
);
578 case D3DDECLTYPE_FLOAT16_2
:
580 D3DXVECTOR4 src_float4
= {0.0f
, 0.0f
, 0.0f
, 1.0f
};
581 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 2);
582 convert_float4(dst
, &src_float4
, type_dst
);
585 case D3DDECLTYPE_FLOAT16_4
:
587 D3DXVECTOR4 src_float4
;
588 D3DXFloat16To32Array((FLOAT
*)&src_float4
, (D3DXFLOAT16
*)src
, 4);
589 convert_float4(dst
, &src_float4
, type_dst
);
594 FIXME("Conversion of D3DDECLTYPE %d to %d not implemented.\n", type_src
, type_dst
);
599 static INT
get_equivalent_declaration_index(D3DVERTEXELEMENT9 orig_declaration
, D3DVERTEXELEMENT9
*declaration
)
603 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
605 if (orig_declaration
.Usage
== declaration
[i
].Usage
606 && orig_declaration
.UsageIndex
== declaration
[i
].UsageIndex
)
615 static HRESULT
convert_vertex_buffer(ID3DXMesh
*mesh_dst
, ID3DXMesh
*mesh_src
)
618 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
619 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = {D3DDECL_END()};
623 UINT num_vertices
= mesh_src
->lpVtbl
->GetNumVertices(mesh_src
);
624 UINT dst_vertex_size
= mesh_dst
->lpVtbl
->GetNumBytesPerVertex(mesh_dst
);
625 UINT src_vertex_size
= mesh_src
->lpVtbl
->GetNumBytesPerVertex(mesh_src
);
627 hr
= mesh_src
->lpVtbl
->GetDeclaration(mesh_src
, orig_declaration
);
628 if (FAILED(hr
)) return hr
;
629 hr
= mesh_dst
->lpVtbl
->GetDeclaration(mesh_dst
, declaration
);
630 if (FAILED(hr
)) return hr
;
632 hr
= mesh_src
->lpVtbl
->LockVertexBuffer(mesh_src
, D3DLOCK_READONLY
, (void**)&vb_src
);
633 if (FAILED(hr
)) goto cleanup
;
634 hr
= mesh_dst
->lpVtbl
->LockVertexBuffer(mesh_dst
, 0, (void**)&vb_dst
);
635 if (FAILED(hr
)) goto cleanup
;
637 /* Clear all new fields by clearing the entire vertex buffer. */
638 memset(vb_dst
, 0, num_vertices
* dst_vertex_size
);
640 for (i
= 0; orig_declaration
[i
].Stream
!= 0xff; i
++)
642 INT eq_idx
= get_equivalent_declaration_index(orig_declaration
[i
], declaration
);
647 for (j
= 0; j
< num_vertices
; j
++)
649 UINT idx_dst
= dst_vertex_size
* j
+ declaration
[eq_idx
].Offset
;
650 UINT idx_src
= src_vertex_size
* j
+ orig_declaration
[i
].Offset
;
651 UINT type_size
= d3dx_decltype_size
[orig_declaration
[i
].Type
];
653 if (orig_declaration
[i
].Type
== declaration
[eq_idx
].Type
)
654 memcpy(&vb_dst
[idx_dst
], &vb_src
[idx_src
], type_size
);
656 convert_component(&vb_dst
[idx_dst
], &vb_src
[idx_src
], declaration
[eq_idx
].Type
, orig_declaration
[i
].Type
);
663 if (vb_dst
) mesh_dst
->lpVtbl
->UnlockVertexBuffer(mesh_dst
);
664 if (vb_src
) mesh_src
->lpVtbl
->UnlockVertexBuffer(mesh_src
);
669 static BOOL
declaration_equals(CONST D3DVERTEXELEMENT9
*declaration1
, CONST D3DVERTEXELEMENT9
*declaration2
)
671 UINT size1
= 0, size2
= 0;
673 /* Find the size of each declaration */
674 while (declaration1
[size1
].Stream
!= 0xff) size1
++;
675 while (declaration2
[size2
].Stream
!= 0xff) size2
++;
677 /* If not same size then they are definitely not equal */
681 /* Check that all components are the same */
682 if (memcmp(declaration1
, declaration2
, size1
*sizeof(*declaration1
)) == 0)
688 static HRESULT WINAPI
ID3DXMeshImpl_CloneMesh(struct ID3DXMesh
*iface
, DWORD options
,
689 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**clone_mesh_out
)
691 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
692 ID3DXMeshImpl
*cloned_this
;
693 ID3DXMesh
*clone_mesh
;
694 D3DVERTEXELEMENT9 orig_declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
695 void *data_in
, *data_out
;
698 BOOL same_declaration
;
700 TRACE("(%p)->(%x,%p,%p,%p)\n", This
, options
, declaration
, device
, clone_mesh_out
);
703 return D3DERR_INVALIDCALL
;
705 hr
= iface
->lpVtbl
->GetDeclaration(iface
, orig_declaration
);
706 if (FAILED(hr
)) return hr
;
708 hr
= D3DXCreateMesh(This
->numfaces
, This
->numvertices
, options
& ~D3DXMESH_VB_SHARE
,
709 declaration
, device
, &clone_mesh
);
710 if (FAILED(hr
)) return hr
;
712 cloned_this
= impl_from_ID3DXMesh(clone_mesh
);
713 vertex_size
= clone_mesh
->lpVtbl
->GetNumBytesPerVertex(clone_mesh
);
714 same_declaration
= declaration_equals(declaration
, orig_declaration
);
716 if (options
& D3DXMESH_VB_SHARE
) {
717 if (!same_declaration
) {
718 hr
= D3DERR_INVALIDCALL
;
721 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
722 /* FIXME: refactor to avoid creating a new vertex buffer */
723 IDirect3DVertexBuffer9_Release(cloned_this
->vertex_buffer
);
724 cloned_this
->vertex_buffer
= This
->vertex_buffer
;
725 } else if (same_declaration
) {
726 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
727 if (FAILED(hr
)) goto error
;
728 hr
= clone_mesh
->lpVtbl
->LockVertexBuffer(clone_mesh
, 0, &data_out
);
730 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
733 memcpy(data_out
, data_in
, This
->numvertices
* vertex_size
);
734 clone_mesh
->lpVtbl
->UnlockVertexBuffer(clone_mesh
);
735 iface
->lpVtbl
->UnlockVertexBuffer(iface
);
737 hr
= convert_vertex_buffer(clone_mesh
, iface
);
738 if (FAILED(hr
)) goto error
;
741 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &data_in
);
742 if (FAILED(hr
)) goto error
;
743 hr
= clone_mesh
->lpVtbl
->LockIndexBuffer(clone_mesh
, 0, &data_out
);
745 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
748 if ((options
^ This
->options
) & D3DXMESH_32BIT
) {
750 if (options
& D3DXMESH_32BIT
) {
751 for (i
= 0; i
< This
->numfaces
* 3; i
++)
752 ((DWORD
*)data_out
)[i
] = ((WORD
*)data_in
)[i
];
754 for (i
= 0; i
< This
->numfaces
* 3; i
++)
755 ((WORD
*)data_out
)[i
] = ((DWORD
*)data_in
)[i
];
758 memcpy(data_out
, data_in
, This
->numfaces
* 3 * (options
& D3DXMESH_32BIT
? 4 : 2));
760 clone_mesh
->lpVtbl
->UnlockIndexBuffer(clone_mesh
);
761 iface
->lpVtbl
->UnlockIndexBuffer(iface
);
763 memcpy(cloned_this
->attrib_buffer
, This
->attrib_buffer
, This
->numfaces
* sizeof(*This
->attrib_buffer
));
765 if (This
->attrib_table_size
)
767 cloned_this
->attrib_table_size
= This
->attrib_table_size
;
768 cloned_this
->attrib_table
= HeapAlloc(GetProcessHeap(), 0, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
769 if (!cloned_this
->attrib_table
) {
773 memcpy(cloned_this
->attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*This
->attrib_table
));
776 *clone_mesh_out
= clone_mesh
;
780 IUnknown_Release(clone_mesh
);
784 static HRESULT WINAPI
ID3DXMeshImpl_GetVertexBuffer(struct ID3DXMesh
*iface
,
785 struct IDirect3DVertexBuffer9
**vertex_buffer
)
787 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
789 TRACE("(%p)->(%p)\n", This
, vertex_buffer
);
791 if (vertex_buffer
== NULL
) return D3DERR_INVALIDCALL
;
792 *vertex_buffer
= This
->vertex_buffer
;
793 IDirect3DVertexBuffer9_AddRef(This
->vertex_buffer
);
798 static HRESULT WINAPI
ID3DXMeshImpl_GetIndexBuffer(struct ID3DXMesh
*iface
,
799 struct IDirect3DIndexBuffer9
**index_buffer
)
801 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
803 TRACE("(%p)->(%p)\n", This
, index_buffer
);
805 if (index_buffer
== NULL
) return D3DERR_INVALIDCALL
;
806 *index_buffer
= This
->index_buffer
;
807 IDirect3DIndexBuffer9_AddRef(This
->index_buffer
);
812 static HRESULT WINAPI
ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
814 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
816 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
818 return IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, data
, flags
);
821 static HRESULT WINAPI
ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh
*iface
)
823 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
825 TRACE("(%p)\n", This
);
827 return IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
830 static HRESULT WINAPI
ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh
*iface
, DWORD flags
, LPVOID
*data
)
832 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
834 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
836 return IDirect3DIndexBuffer9_Lock(This
->index_buffer
, 0, 0, data
, flags
);
839 static HRESULT WINAPI
ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh
*iface
)
841 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
843 TRACE("(%p)\n", This
);
845 return IDirect3DIndexBuffer9_Unlock(This
->index_buffer
);
848 static HRESULT WINAPI
ID3DXMeshImpl_GetAttributeTable(ID3DXMesh
*iface
, D3DXATTRIBUTERANGE
*attrib_table
, DWORD
*attrib_table_size
)
850 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
852 TRACE("(%p)->(%p,%p)\n", This
, attrib_table
, attrib_table_size
);
854 if (attrib_table_size
)
855 *attrib_table_size
= This
->attrib_table_size
;
858 CopyMemory(attrib_table
, This
->attrib_table
, This
->attrib_table_size
* sizeof(*attrib_table
));
873 struct edge_face
*entries
;
876 /* Builds up a map of which face a new edge belongs to. That way the adjacency
877 * of another edge can be looked up. An edge has an adjacent face if there
878 * is an edge going in the opposite direction in the map. For example if the
879 * edge (v1, v2) belongs to face 4, and there is a mapping (v2, v1)->7, then
880 * face 4 and 7 are adjacent.
882 * Each edge might have been replaced with another edge, or none at all. There
883 * is at most one edge to face mapping, i.e. an edge can only belong to one
886 static HRESULT
init_edge_face_map(struct edge_face_map
*edge_face_map
, CONST DWORD
*index_buffer
, CONST DWORD
*point_reps
, CONST DWORD num_faces
)
891 edge_face_map
->lists
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->lists
));
892 if (!edge_face_map
->lists
) return E_OUTOFMEMORY
;
894 edge_face_map
->entries
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(*edge_face_map
->entries
));
895 if (!edge_face_map
->entries
) return E_OUTOFMEMORY
;
898 /* Initialize all lists */
899 for (i
= 0; i
< 3 * num_faces
; i
++)
901 list_init(&edge_face_map
->lists
[i
]);
903 /* Build edge face mapping */
904 for (face
= 0; face
< num_faces
; face
++)
906 for (edge
= 0; edge
< 3; edge
++)
908 DWORD v1
= index_buffer
[3*face
+ edge
];
909 DWORD v2
= index_buffer
[3*face
+ (edge
+1)%3];
910 DWORD new_v1
= point_reps
[v1
]; /* What v1 has been replaced with */
911 DWORD new_v2
= point_reps
[v2
];
913 if (v1
!= v2
) /* Only map non-collapsed edges */
916 edge_face_map
->entries
[i
].v2
= new_v2
;
917 edge_face_map
->entries
[i
].face
= face
;
918 list_add_head(&edge_face_map
->lists
[new_v1
], &edge_face_map
->entries
[i
].entry
);
926 static DWORD
find_adjacent_face(struct edge_face_map
*edge_face_map
, DWORD vertex1
, DWORD vertex2
, CONST DWORD num_faces
)
928 struct edge_face
*edge_face_ptr
;
930 LIST_FOR_EACH_ENTRY(edge_face_ptr
, &edge_face_map
->lists
[vertex2
], struct edge_face
, entry
)
932 if (edge_face_ptr
->v2
== vertex1
)
933 return edge_face_ptr
->face
;
939 static DWORD
*generate_identity_point_reps(DWORD num_vertices
)
941 DWORD
*id_point_reps
;
944 id_point_reps
= HeapAlloc(GetProcessHeap(), 0, num_vertices
* sizeof(*id_point_reps
));
948 for (i
= 0; i
< num_vertices
; i
++)
950 id_point_reps
[i
] = i
;
953 return id_point_reps
;
956 static HRESULT WINAPI
ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh
*iface
, CONST DWORD
*point_reps
, DWORD
*adjacency
)
958 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
960 DWORD num_faces
= iface
->lpVtbl
->GetNumFaces(iface
);
961 DWORD num_vertices
= iface
->lpVtbl
->GetNumVertices(iface
);
962 DWORD options
= iface
->lpVtbl
->GetOptions(iface
);
963 BOOL indices_are_16_bit
= !(options
& D3DXMESH_32BIT
);
968 struct edge_face_map edge_face_map
= {0};
969 CONST DWORD
*point_reps_ptr
= NULL
;
970 DWORD
*id_point_reps
= NULL
;
972 TRACE("(%p)->(%p,%p)\n", This
, point_reps
, adjacency
);
974 if (!adjacency
) return D3DERR_INVALIDCALL
;
976 if (!point_reps
) /* Identity point reps */
978 id_point_reps
= generate_identity_point_reps(num_vertices
);
985 point_reps_ptr
= id_point_reps
;
989 point_reps_ptr
= point_reps
;
992 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, &ib_ptr
);
993 if (FAILED(hr
)) goto cleanup
;
995 if (indices_are_16_bit
)
997 /* Widen 16 bit to 32 bit */
999 WORD
*ib_16bit
= ib_ptr
;
1000 ib
= HeapAlloc(GetProcessHeap(), 0, 3 * num_faces
* sizeof(DWORD
));
1006 for (i
= 0; i
< 3 * num_faces
; i
++)
1008 ib
[i
] = ib_16bit
[i
];
1016 hr
= init_edge_face_map(&edge_face_map
, ib
, point_reps_ptr
, num_faces
);
1017 if (FAILED(hr
)) goto cleanup
;
1019 /* Create adjacency */
1020 for (face
= 0; face
< num_faces
; face
++)
1022 for (edge
= 0; edge
< 3; edge
++)
1024 DWORD v1
= ib
[3*face
+ edge
];
1025 DWORD v2
= ib
[3*face
+ (edge
+1)%3];
1026 DWORD new_v1
= point_reps_ptr
[v1
];
1027 DWORD new_v2
= point_reps_ptr
[v2
];
1030 adj_face
= find_adjacent_face(&edge_face_map
, new_v1
, new_v2
, num_faces
);
1031 adjacency
[3*face
+ edge
] = adj_face
;
1037 HeapFree(GetProcessHeap(), 0, id_point_reps
);
1038 if (indices_are_16_bit
) HeapFree(GetProcessHeap(), 0, ib
);
1039 HeapFree(GetProcessHeap(), 0, edge_face_map
.lists
);
1040 HeapFree(GetProcessHeap(), 0, edge_face_map
.entries
);
1041 if(ib_ptr
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1045 /* ConvertAdjacencyToPointReps helper function.
1047 * Goes around the edges of each face and replaces the vertices in any adjacent
1048 * face's edge with its own vertices(if its vertices have a lower index). This
1049 * way as few as possible low index vertices are shared among the faces. The
1050 * re-ordered index buffer is stored in new_indices.
1052 * The vertices in a point representation must be ordered sequentially, e.g.
1053 * index 5 holds the index of the vertex that replaces vertex 5, i.e. if
1054 * vertex 5 is replaced by vertex 3 then index 5 would contain 3. If no vertex
1055 * replaces it, then it contains the same number as the index itself, e.g.
1056 * index 5 would contain 5. */
1057 static HRESULT
propagate_face_vertices(CONST DWORD
*adjacency
, DWORD
*point_reps
,
1058 CONST DWORD
*indices
, DWORD
*new_indices
,
1059 CONST DWORD face
, CONST DWORD numfaces
)
1061 const unsigned int VERTS_PER_FACE
= 3;
1062 DWORD edge
, opp_edge
;
1063 DWORD face_base
= VERTS_PER_FACE
* face
;
1065 for (edge
= 0; edge
< VERTS_PER_FACE
; edge
++)
1067 DWORD adj_face
= adjacency
[face_base
+ edge
];
1068 DWORD adj_face_base
;
1070 if (adj_face
== -1) /* No adjacent face. */
1072 else if (adj_face
>= numfaces
)
1074 /* This throws exception on Windows */
1075 WARN("Index out of bounds. Got %d expected less than %d.\n",
1076 adj_face
, numfaces
);
1077 return D3DERR_INVALIDCALL
;
1079 adj_face_base
= 3 * adj_face
;
1081 /* Find opposite edge in adjacent face. */
1082 for (opp_edge
= 0; opp_edge
< VERTS_PER_FACE
; opp_edge
++)
1084 DWORD opp_edge_index
= adj_face_base
+ opp_edge
;
1085 if (adjacency
[opp_edge_index
] == face
)
1086 break; /* Found opposite edge. */
1089 /* Replaces vertices in opposite edge with vertices from current edge. */
1090 for (i
= 0; i
< 2; i
++)
1092 DWORD from
= face_base
+ (edge
+ (1 - i
)) % VERTS_PER_FACE
;
1093 DWORD to
= adj_face_base
+ (opp_edge
+ i
) % VERTS_PER_FACE
;
1095 /* Propagate lowest index. */
1096 if (new_indices
[to
] > new_indices
[from
])
1098 new_indices
[to
] = new_indices
[from
];
1099 point_reps
[indices
[to
]] = new_indices
[from
];
1107 static HRESULT WINAPI
ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh
*iface
, CONST DWORD
*adjacency
, DWORD
*point_reps
)
1112 DWORD
*indices
= NULL
;
1113 WORD
*indices_16bit
= NULL
;
1114 DWORD
*new_indices
= NULL
;
1115 const unsigned int VERTS_PER_FACE
= 3;
1117 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1119 TRACE("(%p)->(%p,%p)\n", This
, adjacency
, point_reps
);
1123 WARN("NULL adjacency.\n");
1124 hr
= D3DERR_INVALIDCALL
;
1130 WARN("NULL point_reps.\n");
1131 hr
= D3DERR_INVALIDCALL
;
1135 /* Should never happen as CreateMesh does not allow meshes with 0 faces */
1136 if (This
->numfaces
== 0)
1138 ERR("Number of faces was zero.\n");
1139 hr
= D3DERR_INVALIDCALL
;
1143 new_indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1150 if (This
->options
& D3DXMESH_32BIT
)
1152 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1153 if (FAILED(hr
)) goto cleanup
;
1154 memcpy(new_indices
, indices
, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1158 /* Make a widening copy of indices_16bit into indices and new_indices
1159 * in order to re-use the helper function */
1160 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices_16bit
);
1161 if (FAILED(hr
)) goto cleanup
;
1162 indices
= HeapAlloc(GetProcessHeap(), 0, VERTS_PER_FACE
* This
->numfaces
* sizeof(*indices
));
1168 for (i
= 0; i
< VERTS_PER_FACE
* This
->numfaces
; i
++)
1170 new_indices
[i
] = indices_16bit
[i
];
1171 indices
[i
] = indices_16bit
[i
];
1175 /* Vertices are ordered sequentially in the point representation. */
1176 for (i
= 0; i
< This
->numvertices
; i
++)
1181 /* Propagate vertices with low indices so as few vertices as possible
1182 * are used in the mesh.
1184 for (face
= 0; face
< This
->numfaces
; face
++)
1186 hr
= propagate_face_vertices(adjacency
, point_reps
, indices
, new_indices
, face
, This
->numfaces
);
1187 if (FAILED(hr
)) goto cleanup
;
1189 /* Go in opposite direction to catch all face orderings */
1190 for (face
= 0; face
< This
->numfaces
; face
++)
1192 hr
= propagate_face_vertices(adjacency
, point_reps
,
1193 indices
, new_indices
,
1194 (This
->numfaces
- 1) - face
, This
->numfaces
);
1195 if (FAILED(hr
)) goto cleanup
;
1200 if (This
->options
& D3DXMESH_32BIT
)
1202 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1206 if (indices_16bit
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1207 HeapFree(GetProcessHeap(), 0, indices
);
1209 HeapFree(GetProcessHeap(), 0, new_indices
);
1213 struct vertex_metadata
{
1216 DWORD first_shared_index
;
1219 static int compare_vertex_keys(const void *a
, const void *b
)
1221 const struct vertex_metadata
*left
= a
;
1222 const struct vertex_metadata
*right
= b
;
1223 if (left
->key
== right
->key
)
1225 return left
->key
< right
->key
? -1 : 1;
1228 static HRESULT WINAPI
ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh
*iface
, FLOAT epsilon
, DWORD
*adjacency
)
1230 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1232 BYTE
*vertices
= NULL
;
1233 const DWORD
*indices
= NULL
;
1236 /* sort the vertices by (x + y + z) to quickly find coincident vertices */
1237 struct vertex_metadata
*sorted_vertices
;
1238 /* shared_indices links together identical indices in the index buffer so
1239 * that adjacency checks can be limited to faces sharing a vertex */
1240 DWORD
*shared_indices
= NULL
;
1241 const FLOAT epsilon_sq
= epsilon
* epsilon
;
1244 TRACE("(%p)->(%f,%p)\n", This
, epsilon
, adjacency
);
1247 return D3DERR_INVALIDCALL
;
1249 buffer_size
= This
->numfaces
* 3 * sizeof(*shared_indices
) + This
->numvertices
* sizeof(*sorted_vertices
);
1250 if (!(This
->options
& D3DXMESH_32BIT
))
1251 buffer_size
+= This
->numfaces
* 3 * sizeof(*indices
);
1252 shared_indices
= HeapAlloc(GetProcessHeap(), 0, buffer_size
);
1253 if (!shared_indices
)
1254 return E_OUTOFMEMORY
;
1255 sorted_vertices
= (struct vertex_metadata
*)(shared_indices
+ This
->numfaces
* 3);
1257 hr
= iface
->lpVtbl
->LockVertexBuffer(iface
, D3DLOCK_READONLY
, (void**)&vertices
);
1258 if (FAILED(hr
)) goto cleanup
;
1259 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, D3DLOCK_READONLY
, (void**)&indices
);
1260 if (FAILED(hr
)) goto cleanup
;
1262 if (!(This
->options
& D3DXMESH_32BIT
)) {
1263 const WORD
*word_indices
= (const WORD
*)indices
;
1264 DWORD
*dword_indices
= (DWORD
*)(sorted_vertices
+ This
->numvertices
);
1265 indices
= dword_indices
;
1266 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1267 *dword_indices
++ = *word_indices
++;
1270 vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1271 for (i
= 0; i
< This
->numvertices
; i
++) {
1272 D3DXVECTOR3
*vertex
= (D3DXVECTOR3
*)(vertices
+ vertex_size
* i
);
1273 sorted_vertices
[i
].first_shared_index
= -1;
1274 sorted_vertices
[i
].key
= vertex
->x
+ vertex
->y
+ vertex
->z
;
1275 sorted_vertices
[i
].vertex_index
= i
;
1277 for (i
= 0; i
< This
->numfaces
* 3; i
++) {
1278 DWORD
*first_shared_index
= &sorted_vertices
[indices
[i
]].first_shared_index
;
1279 shared_indices
[i
] = *first_shared_index
;
1280 *first_shared_index
= i
;
1283 qsort(sorted_vertices
, This
->numvertices
, sizeof(*sorted_vertices
), compare_vertex_keys
);
1285 for (i
= 0; i
< This
->numvertices
; i
++) {
1286 struct vertex_metadata
*sorted_vertex_a
= &sorted_vertices
[i
];
1287 D3DXVECTOR3
*vertex_a
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_a
->vertex_index
* vertex_size
);
1288 DWORD shared_index_a
= sorted_vertex_a
->first_shared_index
;
1290 while (shared_index_a
!= -1) {
1292 DWORD shared_index_b
= shared_indices
[shared_index_a
];
1293 struct vertex_metadata
*sorted_vertex_b
= sorted_vertex_a
;
1296 while (shared_index_b
!= -1) {
1297 /* faces are adjacent if they have another coincident vertex */
1298 DWORD base_a
= (shared_index_a
/ 3) * 3;
1299 DWORD base_b
= (shared_index_b
/ 3) * 3;
1300 BOOL adjacent
= FALSE
;
1303 for (k
= 0; k
< 3; k
++) {
1304 if (adjacency
[base_b
+ k
] == shared_index_a
/ 3) {
1310 for (k
= 1; k
<= 2; k
++) {
1311 DWORD vertex_index_a
= base_a
+ (shared_index_a
+ k
) % 3;
1312 DWORD vertex_index_b
= base_b
+ (shared_index_b
+ (3 - k
)) % 3;
1313 adjacent
= indices
[vertex_index_a
] == indices
[vertex_index_b
];
1314 if (!adjacent
&& epsilon
>= 0.0f
) {
1315 D3DXVECTOR3 delta
= {0.0f
, 0.0f
, 0.0f
};
1318 D3DXVec3Subtract(&delta
,
1319 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_a
] * vertex_size
),
1320 (D3DXVECTOR3
*)(vertices
+ indices
[vertex_index_b
] * vertex_size
));
1321 length_sq
= D3DXVec3LengthSq(&delta
);
1322 adjacent
= epsilon
== 0.0f
? length_sq
== 0.0f
: length_sq
< epsilon_sq
;
1325 DWORD adj_a
= base_a
+ 2 - (vertex_index_a
+ shared_index_a
+ 1) % 3;
1326 DWORD adj_b
= base_b
+ 2 - (vertex_index_b
+ shared_index_b
+ 1) % 3;
1327 if (adjacency
[adj_a
] == -1 && adjacency
[adj_b
] == -1) {
1328 adjacency
[adj_a
] = base_b
/ 3;
1329 adjacency
[adj_b
] = base_a
/ 3;
1336 shared_index_b
= shared_indices
[shared_index_b
];
1338 while (++j
< This
->numvertices
) {
1339 D3DXVECTOR3
*vertex_b
;
1342 if (sorted_vertex_b
->key
- sorted_vertex_a
->key
> epsilon
* 3.0f
) {
1343 /* no more coincident vertices to try */
1344 j
= This
->numvertices
;
1347 /* check for coincidence */
1348 vertex_b
= (D3DXVECTOR3
*)(vertices
+ sorted_vertex_b
->vertex_index
* vertex_size
);
1349 if (fabsf(vertex_a
->x
- vertex_b
->x
) <= epsilon
&&
1350 fabsf(vertex_a
->y
- vertex_b
->y
) <= epsilon
&&
1351 fabsf(vertex_a
->z
- vertex_b
->z
) <= epsilon
)
1356 if (j
>= This
->numvertices
)
1358 shared_index_b
= sorted_vertex_b
->first_shared_index
;
1361 sorted_vertex_a
->first_shared_index
= shared_indices
[sorted_vertex_a
->first_shared_index
];
1362 shared_index_a
= sorted_vertex_a
->first_shared_index
;
1368 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1369 if (vertices
) iface
->lpVtbl
->UnlockVertexBuffer(iface
);
1370 HeapFree(GetProcessHeap(), 0, shared_indices
);
1374 static HRESULT WINAPI
ID3DXMeshImpl_UpdateSemantics(ID3DXMesh
*iface
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
1377 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1378 UINT vertex_declaration_size
;
1381 TRACE("(%p)->(%p)\n", This
, declaration
);
1385 WARN("Invalid declaration. Can't use NULL declaration.\n");
1386 return D3DERR_INVALIDCALL
;
1389 /* New declaration must be same size as original */
1390 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
1391 if (vertex_declaration_size
!= This
->vertex_declaration_size
)
1393 WARN("Invalid declaration. New vertex size does not match the original vertex size.\n");
1394 return D3DERR_INVALIDCALL
;
1397 /* New declaration must not contain non-zero Stream value */
1398 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
1400 if (declaration
[i
].Stream
!= 0)
1402 WARN("Invalid declaration. New declaration contains non-zero Stream value.\n");
1403 return D3DERR_INVALIDCALL
;
1407 This
->num_elem
= i
+ 1;
1408 copy_declaration(This
->cached_declaration
, declaration
, This
->num_elem
);
1410 if (This
->vertex_declaration
)
1411 IDirect3DVertexDeclaration9_Release(This
->vertex_declaration
);
1413 /* An application can pass an invalid declaration to UpdateSemantics and
1414 * still expect D3D_OK (see tests). If the declaration is invalid, then
1415 * subsequent calls to DrawSubset will fail. This is handled by setting the
1416 * vertex declaration to NULL.
1417 * GetDeclaration, GetNumBytesPerVertex must, however, use the new
1418 * invalid declaration. This is handled by them using the cached vertex
1419 * declaration instead of the actual vertex declaration.
1421 hr
= IDirect3DDevice9_CreateVertexDeclaration(This
->device
,
1423 &This
->vertex_declaration
);
1426 WARN("Using invalid declaration. Calls to DrawSubset will fail.\n");
1427 This
->vertex_declaration
= NULL
;
1434 static HRESULT WINAPI
ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh
*iface
, DWORD flags
, DWORD
**data
)
1436 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1438 TRACE("(%p)->(%u,%p)\n", This
, flags
, data
);
1440 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
1442 if (!(flags
& D3DLOCK_READONLY
)) {
1443 D3DXATTRIBUTERANGE
*attrib_table
= This
->attrib_table
;
1444 This
->attrib_table_size
= 0;
1445 This
->attrib_table
= NULL
;
1446 HeapFree(GetProcessHeap(), 0, attrib_table
);
1449 *data
= This
->attrib_buffer
;
1454 static HRESULT WINAPI
ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh
*iface
)
1456 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1459 TRACE("(%p)\n", This
);
1461 lock_count
= InterlockedDecrement(&This
->attrib_buffer_lock_count
);
1463 if (lock_count
< 0) {
1464 InterlockedIncrement(&This
->attrib_buffer_lock_count
);
1465 return D3DERR_INVALIDCALL
;
1471 static HRESULT WINAPI
ID3DXMeshImpl_Optimize(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1472 DWORD
*adjacency_out
, DWORD
*face_remap
, ID3DXBuffer
**vertex_remap
, ID3DXMesh
**opt_mesh
)
1474 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1476 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
] = { D3DDECL_END() };
1477 ID3DXMesh
*optimized_mesh
;
1479 TRACE("(%p)->(%x,%p,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
, opt_mesh
);
1482 return D3DERR_INVALIDCALL
;
1484 hr
= iface
->lpVtbl
->GetDeclaration(iface
, declaration
);
1485 if (FAILED(hr
)) return hr
;
1487 hr
= iface
->lpVtbl
->CloneMesh(iface
, This
->options
, declaration
, This
->device
, &optimized_mesh
);
1488 if (FAILED(hr
)) return hr
;
1490 hr
= optimized_mesh
->lpVtbl
->OptimizeInplace(optimized_mesh
, flags
, adjacency_in
, adjacency_out
, face_remap
, vertex_remap
);
1492 *opt_mesh
= optimized_mesh
;
1494 IUnknown_Release(optimized_mesh
);
1498 /* Creates a vertex_remap that removes unused vertices.
1499 * Indices are updated according to the vertex_remap. */
1500 static HRESULT
compact_mesh(ID3DXMeshImpl
*This
, DWORD
*indices
, DWORD
*new_num_vertices
, ID3DXBuffer
**vertex_remap
)
1503 DWORD
*vertex_remap_ptr
;
1504 DWORD num_used_vertices
;
1507 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), vertex_remap
);
1508 if (FAILED(hr
)) return hr
;
1509 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(*vertex_remap
);
1511 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1512 vertex_remap_ptr
[indices
[i
]] = 1;
1514 /* create old->new vertex mapping */
1515 num_used_vertices
= 0;
1516 for (i
= 0; i
< This
->numvertices
; i
++) {
1517 if (vertex_remap_ptr
[i
])
1518 vertex_remap_ptr
[i
] = num_used_vertices
++;
1520 vertex_remap_ptr
[i
] = -1;
1522 /* convert indices */
1523 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1524 indices
[i
] = vertex_remap_ptr
[indices
[i
]];
1526 /* create new->old vertex mapping */
1527 num_used_vertices
= 0;
1528 for (i
= 0; i
< This
->numvertices
; i
++) {
1529 if (vertex_remap_ptr
[i
] != -1)
1530 vertex_remap_ptr
[num_used_vertices
++] = i
;
1532 for (i
= num_used_vertices
; i
< This
->numvertices
; i
++)
1533 vertex_remap_ptr
[i
] = -1;
1535 *new_num_vertices
= num_used_vertices
;
1540 /* count the number of unique attribute values in a sorted attribute buffer */
1541 static DWORD
count_attributes(const DWORD
*attrib_buffer
, DWORD numfaces
)
1543 DWORD last_attribute
= attrib_buffer
[0];
1544 DWORD attrib_table_size
= 1;
1546 for (i
= 1; i
< numfaces
; i
++) {
1547 if (attrib_buffer
[i
] != last_attribute
) {
1548 last_attribute
= attrib_buffer
[i
];
1549 attrib_table_size
++;
1552 return attrib_table_size
;
1555 static void fill_attribute_table(DWORD
*attrib_buffer
, DWORD numfaces
, void *indices
,
1556 BOOL is_32bit_indices
, D3DXATTRIBUTERANGE
*attrib_table
)
1558 DWORD attrib_table_size
= 0;
1559 DWORD last_attribute
= attrib_buffer
[0];
1560 DWORD min_vertex
, max_vertex
;
1563 attrib_table
[0].AttribId
= last_attribute
;
1564 attrib_table
[0].FaceStart
= 0;
1565 min_vertex
= (DWORD
)-1;
1567 for (i
= 0; i
< numfaces
; i
++) {
1570 if (attrib_buffer
[i
] != last_attribute
) {
1571 last_attribute
= attrib_buffer
[i
];
1572 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1573 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1574 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1575 attrib_table_size
++;
1576 attrib_table
[attrib_table_size
].AttribId
= attrib_buffer
[i
];
1577 attrib_table
[attrib_table_size
].FaceStart
= i
;
1578 min_vertex
= (DWORD
)-1;
1581 for (j
= 0; j
< 3; j
++) {
1582 DWORD vertex_index
= is_32bit_indices
? ((DWORD
*)indices
)[i
* 3 + j
] : ((WORD
*)indices
)[i
* 3 + j
];
1583 if (vertex_index
< min_vertex
)
1584 min_vertex
= vertex_index
;
1585 if (vertex_index
> max_vertex
)
1586 max_vertex
= vertex_index
;
1589 attrib_table
[attrib_table_size
].FaceCount
= i
- attrib_table
[attrib_table_size
].FaceStart
;
1590 attrib_table
[attrib_table_size
].VertexStart
= min_vertex
;
1591 attrib_table
[attrib_table_size
].VertexCount
= max_vertex
- min_vertex
+ 1;
1592 attrib_table_size
++;
1595 static int attrib_entry_compare(const DWORD
**a
, const DWORD
**b
)
1597 const DWORD
*ptr_a
= *a
;
1598 const DWORD
*ptr_b
= *b
;
1599 int delta
= *ptr_a
- *ptr_b
;
1604 delta
= ptr_a
- ptr_b
; /* for stable sort */
1608 /* Create face_remap, a new attribute buffer for attribute sort optimization. */
1609 static HRESULT
remap_faces_for_attrsort(ID3DXMeshImpl
*This
, const DWORD
*indices
,
1610 const DWORD
*attrib_buffer
, DWORD
**sorted_attrib_buffer
, DWORD
**face_remap
)
1612 const DWORD
**sorted_attrib_ptr_buffer
= NULL
;
1615 *face_remap
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(**face_remap
));
1616 sorted_attrib_ptr_buffer
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* sizeof(*sorted_attrib_ptr_buffer
));
1617 if (!*face_remap
|| !sorted_attrib_ptr_buffer
) {
1618 HeapFree(GetProcessHeap(), 0, sorted_attrib_ptr_buffer
);
1619 return E_OUTOFMEMORY
;
1621 for (i
= 0; i
< This
->numfaces
; i
++)
1622 sorted_attrib_ptr_buffer
[i
] = &attrib_buffer
[i
];
1623 qsort(sorted_attrib_ptr_buffer
, This
->numfaces
, sizeof(*sorted_attrib_ptr_buffer
),
1624 (int(*)(const void *, const void *))attrib_entry_compare
);
1626 for (i
= 0; i
< This
->numfaces
; i
++)
1628 DWORD old_face
= sorted_attrib_ptr_buffer
[i
] - attrib_buffer
;
1629 (*face_remap
)[old_face
] = i
;
1632 /* overwrite sorted_attrib_ptr_buffer with the values themselves */
1633 *sorted_attrib_buffer
= (DWORD
*)sorted_attrib_ptr_buffer
;
1634 for (i
= 0; i
< This
->numfaces
; i
++)
1635 (*sorted_attrib_buffer
)[(*face_remap
)[i
]] = attrib_buffer
[i
];
1640 static HRESULT WINAPI
ID3DXMeshImpl_OptimizeInplace(ID3DXMesh
*iface
, DWORD flags
, const DWORD
*adjacency_in
,
1641 DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
1643 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1644 void *indices
= NULL
;
1645 DWORD
*attrib_buffer
= NULL
;
1647 ID3DXBuffer
*vertex_remap
= NULL
;
1648 DWORD
*face_remap
= NULL
; /* old -> new mapping */
1649 DWORD
*dword_indices
= NULL
;
1650 DWORD new_num_vertices
= 0;
1651 DWORD new_num_alloc_vertices
= 0;
1652 IDirect3DVertexBuffer9
*vertex_buffer
= NULL
;
1653 DWORD
*sorted_attrib_buffer
= NULL
;
1656 TRACE("(%p)->(%x,%p,%p,%p,%p)\n", This
, flags
, adjacency_in
, adjacency_out
, face_remap_out
, vertex_remap_out
);
1659 return D3DERR_INVALIDCALL
;
1660 if (!adjacency_in
&& (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)))
1661 return D3DERR_INVALIDCALL
;
1662 if ((flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
)) == (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1663 return D3DERR_INVALIDCALL
;
1665 if (flags
& (D3DXMESHOPT_VERTEXCACHE
| D3DXMESHOPT_STRIPREORDER
))
1667 if (flags
& D3DXMESHOPT_VERTEXCACHE
)
1668 FIXME("D3DXMESHOPT_VERTEXCACHE not implemented.\n");
1669 if (flags
& D3DXMESHOPT_STRIPREORDER
)
1670 FIXME("D3DXMESHOPT_STRIPREORDER not implemented.\n");
1674 hr
= iface
->lpVtbl
->LockIndexBuffer(iface
, 0, &indices
);
1675 if (FAILED(hr
)) goto cleanup
;
1677 dword_indices
= HeapAlloc(GetProcessHeap(), 0, This
->numfaces
* 3 * sizeof(DWORD
));
1678 if (!dword_indices
) return E_OUTOFMEMORY
;
1679 if (This
->options
& D3DXMESH_32BIT
) {
1680 memcpy(dword_indices
, indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1682 WORD
*word_indices
= indices
;
1683 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1684 dword_indices
[i
] = *word_indices
++;
1687 if ((flags
& (D3DXMESHOPT_COMPACT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_ATTRSORT
)) == D3DXMESHOPT_COMPACT
)
1689 new_num_alloc_vertices
= This
->numvertices
;
1690 hr
= compact_mesh(This
, dword_indices
, &new_num_vertices
, &vertex_remap
);
1691 if (FAILED(hr
)) goto cleanup
;
1692 } else if (flags
& D3DXMESHOPT_ATTRSORT
) {
1693 if (!(flags
& D3DXMESHOPT_IGNOREVERTS
))
1695 FIXME("D3DXMESHOPT_ATTRSORT vertex reordering not implemented.\n");
1700 hr
= iface
->lpVtbl
->LockAttributeBuffer(iface
, 0, &attrib_buffer
);
1701 if (FAILED(hr
)) goto cleanup
;
1703 hr
= remap_faces_for_attrsort(This
, dword_indices
, attrib_buffer
, &sorted_attrib_buffer
, &face_remap
);
1704 if (FAILED(hr
)) goto cleanup
;
1709 /* reorder the vertices using vertex_remap */
1710 D3DVERTEXBUFFER_DESC vertex_desc
;
1711 DWORD
*vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1712 DWORD vertex_size
= iface
->lpVtbl
->GetNumBytesPerVertex(iface
);
1713 BYTE
*orig_vertices
;
1716 hr
= IDirect3DVertexBuffer9_GetDesc(This
->vertex_buffer
, &vertex_desc
);
1717 if (FAILED(hr
)) goto cleanup
;
1719 hr
= IDirect3DDevice9_CreateVertexBuffer(This
->device
, new_num_alloc_vertices
* vertex_size
,
1720 vertex_desc
.Usage
, This
->fvf
, vertex_desc
.Pool
, &vertex_buffer
, NULL
);
1721 if (FAILED(hr
)) goto cleanup
;
1723 hr
= IDirect3DVertexBuffer9_Lock(This
->vertex_buffer
, 0, 0, (void**)&orig_vertices
, D3DLOCK_READONLY
);
1724 if (FAILED(hr
)) goto cleanup
;
1726 hr
= IDirect3DVertexBuffer9_Lock(vertex_buffer
, 0, 0, (void**)&new_vertices
, 0);
1728 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1732 for (i
= 0; i
< new_num_vertices
; i
++)
1733 memcpy(new_vertices
+ i
* vertex_size
, orig_vertices
+ vertex_remap_ptr
[i
] * vertex_size
, vertex_size
);
1735 IDirect3DVertexBuffer9_Unlock(This
->vertex_buffer
);
1736 IDirect3DVertexBuffer9_Unlock(vertex_buffer
);
1737 } else if (vertex_remap_out
) {
1738 DWORD
*vertex_remap_ptr
;
1740 hr
= D3DXCreateBuffer(This
->numvertices
* sizeof(DWORD
), &vertex_remap
);
1741 if (FAILED(hr
)) goto cleanup
;
1742 vertex_remap_ptr
= ID3DXBuffer_GetBufferPointer(vertex_remap
);
1743 for (i
= 0; i
< This
->numvertices
; i
++)
1744 *vertex_remap_ptr
++ = i
;
1747 if (flags
& D3DXMESHOPT_ATTRSORT
)
1749 D3DXATTRIBUTERANGE
*attrib_table
;
1750 DWORD attrib_table_size
;
1752 attrib_table_size
= count_attributes(sorted_attrib_buffer
, This
->numfaces
);
1753 attrib_table
= HeapAlloc(GetProcessHeap(), 0, attrib_table_size
* sizeof(*attrib_table
));
1754 if (!attrib_table
) {
1759 memcpy(attrib_buffer
, sorted_attrib_buffer
, This
->numfaces
* sizeof(*attrib_buffer
));
1761 /* reorder the indices using face_remap */
1762 if (This
->options
& D3DXMESH_32BIT
) {
1763 for (i
= 0; i
< This
->numfaces
; i
++)
1764 memcpy((DWORD
*)indices
+ face_remap
[i
] * 3, dword_indices
+ i
* 3, 3 * sizeof(DWORD
));
1766 WORD
*word_indices
= indices
;
1767 for (i
= 0; i
< This
->numfaces
; i
++) {
1768 DWORD new_pos
= face_remap
[i
] * 3;
1769 DWORD old_pos
= i
* 3;
1770 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1771 word_indices
[new_pos
++] = dword_indices
[old_pos
++];
1772 word_indices
[new_pos
] = dword_indices
[old_pos
];
1776 fill_attribute_table(attrib_buffer
, This
->numfaces
, indices
,
1777 This
->options
& D3DXMESH_32BIT
, attrib_table
);
1779 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1780 This
->attrib_table
= attrib_table
;
1781 This
->attrib_table_size
= attrib_table_size
;
1783 if (This
->options
& D3DXMESH_32BIT
) {
1784 memcpy(indices
, dword_indices
, This
->numfaces
* 3 * sizeof(DWORD
));
1786 WORD
*word_indices
= indices
;
1787 for (i
= 0; i
< This
->numfaces
* 3; i
++)
1788 *word_indices
++ = dword_indices
[i
];
1792 if (adjacency_out
) {
1794 for (i
= 0; i
< This
->numfaces
; i
++) {
1795 DWORD old_pos
= i
* 3;
1796 DWORD new_pos
= face_remap
[i
] * 3;
1797 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1798 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1799 adjacency_out
[new_pos
++] = face_remap
[adjacency_in
[old_pos
++]];
1802 memcpy(adjacency_out
, adjacency_in
, This
->numfaces
* 3 * sizeof(*adjacency_out
));
1805 if (face_remap_out
) {
1807 for (i
= 0; i
< This
->numfaces
; i
++)
1808 face_remap_out
[face_remap
[i
]] = i
;
1810 for (i
= 0; i
< This
->numfaces
; i
++)
1811 face_remap_out
[i
] = i
;
1814 if (vertex_remap_out
)
1815 *vertex_remap_out
= vertex_remap
;
1816 vertex_remap
= NULL
;
1818 if (vertex_buffer
) {
1819 IDirect3DVertexBuffer9_Release(This
->vertex_buffer
);
1820 This
->vertex_buffer
= vertex_buffer
;
1821 vertex_buffer
= NULL
;
1822 This
->numvertices
= new_num_vertices
;
1827 HeapFree(GetProcessHeap(), 0, sorted_attrib_buffer
);
1828 HeapFree(GetProcessHeap(), 0, face_remap
);
1829 HeapFree(GetProcessHeap(), 0, dword_indices
);
1830 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
1831 if (vertex_buffer
) IDirect3DVertexBuffer9_Release(vertex_buffer
);
1832 if (attrib_buffer
) iface
->lpVtbl
->UnlockAttributeBuffer(iface
);
1833 if (indices
) iface
->lpVtbl
->UnlockIndexBuffer(iface
);
1837 static HRESULT WINAPI
ID3DXMeshImpl_SetAttributeTable(ID3DXMesh
*iface
, CONST D3DXATTRIBUTERANGE
*attrib_table
, DWORD attrib_table_size
)
1839 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(iface
);
1840 D3DXATTRIBUTERANGE
*new_table
= NULL
;
1842 TRACE("(%p)->(%p,%u)\n", This
, attrib_table
, attrib_table_size
);
1844 if (attrib_table_size
) {
1845 size_t size
= attrib_table_size
* sizeof(*attrib_table
);
1847 new_table
= HeapAlloc(GetProcessHeap(), 0, size
);
1849 return E_OUTOFMEMORY
;
1851 CopyMemory(new_table
, attrib_table
, size
);
1852 } else if (attrib_table
) {
1853 return D3DERR_INVALIDCALL
;
1855 HeapFree(GetProcessHeap(), 0, This
->attrib_table
);
1856 This
->attrib_table
= new_table
;
1857 This
->attrib_table_size
= attrib_table_size
;
1862 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl
=
1864 /*** IUnknown methods ***/
1865 ID3DXMeshImpl_QueryInterface
,
1866 ID3DXMeshImpl_AddRef
,
1867 ID3DXMeshImpl_Release
,
1868 /*** ID3DXBaseMesh ***/
1869 ID3DXMeshImpl_DrawSubset
,
1870 ID3DXMeshImpl_GetNumFaces
,
1871 ID3DXMeshImpl_GetNumVertices
,
1872 ID3DXMeshImpl_GetFVF
,
1873 ID3DXMeshImpl_GetDeclaration
,
1874 ID3DXMeshImpl_GetNumBytesPerVertex
,
1875 ID3DXMeshImpl_GetOptions
,
1876 ID3DXMeshImpl_GetDevice
,
1877 ID3DXMeshImpl_CloneMeshFVF
,
1878 ID3DXMeshImpl_CloneMesh
,
1879 ID3DXMeshImpl_GetVertexBuffer
,
1880 ID3DXMeshImpl_GetIndexBuffer
,
1881 ID3DXMeshImpl_LockVertexBuffer
,
1882 ID3DXMeshImpl_UnlockVertexBuffer
,
1883 ID3DXMeshImpl_LockIndexBuffer
,
1884 ID3DXMeshImpl_UnlockIndexBuffer
,
1885 ID3DXMeshImpl_GetAttributeTable
,
1886 ID3DXMeshImpl_ConvertPointRepsToAdjacency
,
1887 ID3DXMeshImpl_ConvertAdjacencyToPointReps
,
1888 ID3DXMeshImpl_GenerateAdjacency
,
1889 ID3DXMeshImpl_UpdateSemantics
,
1891 ID3DXMeshImpl_LockAttributeBuffer
,
1892 ID3DXMeshImpl_UnlockAttributeBuffer
,
1893 ID3DXMeshImpl_Optimize
,
1894 ID3DXMeshImpl_OptimizeInplace
,
1895 ID3DXMeshImpl_SetAttributeTable
1898 /*************************************************************************
1901 BOOL WINAPI
D3DXBoxBoundProbe(CONST D3DXVECTOR3
*pmin
, CONST D3DXVECTOR3
*pmax
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
1903 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algorithm
1904 Amy Williams University of Utah
1905 Steve Barrus University of Utah
1906 R. Keith Morley University of Utah
1907 Peter Shirley University of Utah
1909 International Conference on Computer Graphics and Interactive Techniques archive
1910 ACM SIGGRAPH 2005 Courses
1911 Los Angeles, California
1913 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
1915 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
1916 against each slab, if there's anything left of the ray after we're
1917 done we've got an intersection of the ray with the box.
1921 FLOAT div
, tmin
, tmax
, tymin
, tymax
, tzmin
, tzmax
;
1923 div
= 1.0f
/ praydirection
->x
;
1926 tmin
= ( pmin
->x
- prayposition
->x
) * div
;
1927 tmax
= ( pmax
->x
- prayposition
->x
) * div
;
1931 tmin
= ( pmax
->x
- prayposition
->x
) * div
;
1932 tmax
= ( pmin
->x
- prayposition
->x
) * div
;
1935 if ( tmax
< 0.0f
) return FALSE
;
1937 div
= 1.0f
/ praydirection
->y
;
1940 tymin
= ( pmin
->y
- prayposition
->y
) * div
;
1941 tymax
= ( pmax
->y
- prayposition
->y
) * div
;
1945 tymin
= ( pmax
->y
- prayposition
->y
) * div
;
1946 tymax
= ( pmin
->y
- prayposition
->y
) * div
;
1949 if ( ( tymax
< 0.0f
) || ( tmin
> tymax
) || ( tymin
> tmax
) ) return FALSE
;
1951 if ( tymin
> tmin
) tmin
= tymin
;
1952 if ( tymax
< tmax
) tmax
= tymax
;
1954 div
= 1.0f
/ praydirection
->z
;
1957 tzmin
= ( pmin
->z
- prayposition
->z
) * div
;
1958 tzmax
= ( pmax
->z
- prayposition
->z
) * div
;
1962 tzmin
= ( pmax
->z
- prayposition
->z
) * div
;
1963 tzmax
= ( pmin
->z
- prayposition
->z
) * div
;
1966 if ( (tzmax
< 0.0f
) || ( tmin
> tzmax
) || ( tzmin
> tmax
) ) return FALSE
;
1971 /*************************************************************************
1972 * D3DXComputeBoundingBox
1974 HRESULT WINAPI
D3DXComputeBoundingBox(CONST D3DXVECTOR3
*pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pmin
, D3DXVECTOR3
*pmax
)
1979 if( !pfirstposition
|| !pmin
|| !pmax
) return D3DERR_INVALIDCALL
;
1981 *pmin
= *pfirstposition
;
1984 for(i
=0; i
<numvertices
; i
++)
1986 vec
= *( (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
) );
1988 if ( vec
.x
< pmin
->x
) pmin
->x
= vec
.x
;
1989 if ( vec
.x
> pmax
->x
) pmax
->x
= vec
.x
;
1991 if ( vec
.y
< pmin
->y
) pmin
->y
= vec
.y
;
1992 if ( vec
.y
> pmax
->y
) pmax
->y
= vec
.y
;
1994 if ( vec
.z
< pmin
->z
) pmin
->z
= vec
.z
;
1995 if ( vec
.z
> pmax
->z
) pmax
->z
= vec
.z
;
2001 /*************************************************************************
2002 * D3DXComputeBoundingSphere
2004 HRESULT WINAPI
D3DXComputeBoundingSphere(CONST D3DXVECTOR3
* pfirstposition
, DWORD numvertices
, DWORD dwstride
, D3DXVECTOR3
*pcenter
, FLOAT
*pradius
)
2010 if( !pfirstposition
|| !pcenter
|| !pradius
) return D3DERR_INVALIDCALL
;
2017 for(i
=0; i
<numvertices
; i
++)
2018 D3DXVec3Add(&temp
, &temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
));
2020 D3DXVec3Scale(pcenter
, &temp
, 1.0f
/ numvertices
);
2022 for(i
=0; i
<numvertices
; i
++)
2024 d
= D3DXVec3Length(D3DXVec3Subtract(&temp
, (const D3DXVECTOR3
*)((const char*)pfirstposition
+ dwstride
* i
), pcenter
));
2025 if ( d
> *pradius
) *pradius
= d
;
2030 static void append_decl_element(D3DVERTEXELEMENT9
*declaration
, UINT
*idx
, UINT
*offset
,
2031 D3DDECLTYPE type
, D3DDECLUSAGE usage
, UINT usage_idx
)
2033 declaration
[*idx
].Stream
= 0;
2034 declaration
[*idx
].Offset
= *offset
;
2035 declaration
[*idx
].Type
= type
;
2036 declaration
[*idx
].Method
= D3DDECLMETHOD_DEFAULT
;
2037 declaration
[*idx
].Usage
= usage
;
2038 declaration
[*idx
].UsageIndex
= usage_idx
;
2040 *offset
+= d3dx_decltype_size
[type
];
2044 /*************************************************************************
2045 * D3DXDeclaratorFromFVF
2047 HRESULT WINAPI
D3DXDeclaratorFromFVF(DWORD fvf
, D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
])
2049 static const D3DVERTEXELEMENT9 end_element
= D3DDECL_END();
2050 DWORD tex_count
= (fvf
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2051 unsigned int offset
= 0;
2052 unsigned int idx
= 0;
2055 TRACE("fvf %#x, declaration %p.\n", fvf
, declaration
);
2057 if (fvf
& (D3DFVF_RESERVED0
| D3DFVF_RESERVED2
)) return D3DERR_INVALIDCALL
;
2059 if (fvf
& D3DFVF_POSITION_MASK
)
2061 BOOL has_blend
= (fvf
& D3DFVF_XYZB5
) >= D3DFVF_XYZB1
;
2062 DWORD blend_count
= 1 + (((fvf
& D3DFVF_XYZB5
) - D3DFVF_XYZB1
) >> 1);
2063 BOOL has_blend_idx
= (fvf
& D3DFVF_LASTBETA_D3DCOLOR
) || (fvf
& D3DFVF_LASTBETA_UBYTE4
);
2065 if (has_blend_idx
) --blend_count
;
2067 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZW
2068 || (has_blend
&& blend_count
> 4))
2069 return D3DERR_INVALIDCALL
;
2071 if ((fvf
& D3DFVF_POSITION_MASK
) == D3DFVF_XYZRHW
)
2072 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_POSITIONT
, 0);
2074 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_POSITION
, 0);
2078 switch (blend_count
)
2083 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2086 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2089 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2092 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_BLENDWEIGHT
, 0);
2095 ERR("Invalid blend count %u.\n", blend_count
);
2101 if (fvf
& D3DFVF_LASTBETA_UBYTE4
)
2102 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_UBYTE4
, D3DDECLUSAGE_BLENDINDICES
, 0);
2103 else if (fvf
& D3DFVF_LASTBETA_D3DCOLOR
)
2104 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_BLENDINDICES
, 0);
2109 if (fvf
& D3DFVF_NORMAL
)
2110 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_NORMAL
, 0);
2111 if (fvf
& D3DFVF_PSIZE
)
2112 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_PSIZE
, 0);
2113 if (fvf
& D3DFVF_DIFFUSE
)
2114 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 0);
2115 if (fvf
& D3DFVF_SPECULAR
)
2116 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_D3DCOLOR
, D3DDECLUSAGE_COLOR
, 1);
2118 for (i
= 0; i
< tex_count
; ++i
)
2120 switch ((fvf
>> (16 + 2 * i
)) & 0x03)
2122 case D3DFVF_TEXTUREFORMAT1
:
2123 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT1
, D3DDECLUSAGE_TEXCOORD
, i
);
2125 case D3DFVF_TEXTUREFORMAT2
:
2126 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT2
, D3DDECLUSAGE_TEXCOORD
, i
);
2128 case D3DFVF_TEXTUREFORMAT3
:
2129 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT3
, D3DDECLUSAGE_TEXCOORD
, i
);
2131 case D3DFVF_TEXTUREFORMAT4
:
2132 append_decl_element(declaration
, &idx
, &offset
, D3DDECLTYPE_FLOAT4
, D3DDECLUSAGE_TEXCOORD
, i
);
2137 declaration
[idx
] = end_element
;
2142 /*************************************************************************
2143 * D3DXFVFFromDeclarator
2145 HRESULT WINAPI
D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9
*declaration
, DWORD
*fvf
)
2147 unsigned int i
= 0, texture
, offset
;
2149 TRACE("(%p, %p)\n", declaration
, fvf
);
2152 if (declaration
[0].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITION
)
2154 if ((declaration
[1].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2155 declaration
[1].UsageIndex
== 0) &&
2156 (declaration
[2].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&&
2157 declaration
[2].UsageIndex
== 0))
2159 return D3DERR_INVALIDCALL
;
2161 else if ((declaration
[1].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[1].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2162 declaration
[1].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[1].UsageIndex
== 0)
2164 if (declaration
[1].Type
== D3DDECLTYPE_UBYTE4
)
2166 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_UBYTE4
;
2170 *fvf
|= D3DFVF_XYZB1
| D3DFVF_LASTBETA_D3DCOLOR
;
2174 else if (declaration
[1].Type
<= D3DDECLTYPE_FLOAT4
&& declaration
[1].Usage
== D3DDECLUSAGE_BLENDWEIGHT
&&
2175 declaration
[1].UsageIndex
== 0)
2177 if ((declaration
[2].Type
== D3DDECLTYPE_UBYTE4
|| declaration
[2].Type
== D3DDECLTYPE_D3DCOLOR
) &&
2178 declaration
[2].Usage
== D3DDECLUSAGE_BLENDINDICES
&& declaration
[2].UsageIndex
== 0)
2180 if (declaration
[2].Type
== D3DDECLTYPE_UBYTE4
)
2182 *fvf
|= D3DFVF_LASTBETA_UBYTE4
;
2186 *fvf
|= D3DFVF_LASTBETA_D3DCOLOR
;
2188 switch (declaration
[1].Type
)
2190 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB2
; break;
2191 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB3
; break;
2192 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB4
; break;
2193 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB5
; break;
2199 switch (declaration
[1].Type
)
2201 case D3DDECLTYPE_FLOAT1
: *fvf
|= D3DFVF_XYZB1
; break;
2202 case D3DDECLTYPE_FLOAT2
: *fvf
|= D3DFVF_XYZB2
; break;
2203 case D3DDECLTYPE_FLOAT3
: *fvf
|= D3DFVF_XYZB3
; break;
2204 case D3DDECLTYPE_FLOAT4
: *fvf
|= D3DFVF_XYZB4
; break;
2215 else if (declaration
[0].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[0].Usage
== D3DDECLUSAGE_POSITIONT
&&
2216 declaration
[0].UsageIndex
== 0)
2218 *fvf
|= D3DFVF_XYZRHW
;
2222 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_NORMAL
)
2224 *fvf
|= D3DFVF_NORMAL
;
2227 if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_PSIZE
&&
2228 declaration
[i
].UsageIndex
== 0)
2230 *fvf
|= D3DFVF_PSIZE
;
2233 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2234 declaration
[i
].UsageIndex
== 0)
2236 *fvf
|= D3DFVF_DIFFUSE
;
2239 if (declaration
[i
].Type
== D3DDECLTYPE_D3DCOLOR
&& declaration
[i
].Usage
== D3DDECLUSAGE_COLOR
&&
2240 declaration
[i
].UsageIndex
== 1)
2242 *fvf
|= D3DFVF_SPECULAR
;
2246 for (texture
= 0; texture
< D3DDP_MAXTEXCOORD
; i
++, texture
++)
2248 if (declaration
[i
].Stream
== 0xFF)
2252 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT1
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2253 declaration
[i
].UsageIndex
== texture
)
2255 *fvf
|= D3DFVF_TEXCOORDSIZE1(declaration
[i
].UsageIndex
);
2257 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT2
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2258 declaration
[i
].UsageIndex
== texture
)
2260 *fvf
|= D3DFVF_TEXCOORDSIZE2(declaration
[i
].UsageIndex
);
2262 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT3
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2263 declaration
[i
].UsageIndex
== texture
)
2265 *fvf
|= D3DFVF_TEXCOORDSIZE3(declaration
[i
].UsageIndex
);
2267 else if (declaration
[i
].Type
== D3DDECLTYPE_FLOAT4
&& declaration
[i
].Usage
== D3DDECLUSAGE_TEXCOORD
&&
2268 declaration
[i
].UsageIndex
== texture
)
2270 *fvf
|= D3DFVF_TEXCOORDSIZE4(declaration
[i
].UsageIndex
);
2274 return D3DERR_INVALIDCALL
;
2278 *fvf
|= (texture
<< D3DFVF_TEXCOUNT_SHIFT
);
2280 for (offset
= 0, i
= 0; declaration
[i
].Stream
!= 0xFF;
2281 offset
+= d3dx_decltype_size
[declaration
[i
].Type
], i
++)
2283 if (declaration
[i
].Offset
!= offset
)
2285 return D3DERR_INVALIDCALL
;
2292 /*************************************************************************
2293 * D3DXGetFVFVertexSize
2295 static UINT
Get_TexCoord_Size_From_FVF(DWORD FVF
, int tex_num
)
2297 return (((((FVF
) >> (16 + (2 * (tex_num
)))) + 1) & 0x03) + 1);
2300 UINT WINAPI
D3DXGetFVFVertexSize(DWORD FVF
)
2304 UINT numTextures
= (FVF
& D3DFVF_TEXCOUNT_MASK
) >> D3DFVF_TEXCOUNT_SHIFT
;
2306 if (FVF
& D3DFVF_NORMAL
) size
+= sizeof(D3DXVECTOR3
);
2307 if (FVF
& D3DFVF_DIFFUSE
) size
+= sizeof(DWORD
);
2308 if (FVF
& D3DFVF_SPECULAR
) size
+= sizeof(DWORD
);
2309 if (FVF
& D3DFVF_PSIZE
) size
+= sizeof(DWORD
);
2311 switch (FVF
& D3DFVF_POSITION_MASK
)
2313 case D3DFVF_XYZ
: size
+= sizeof(D3DXVECTOR3
); break;
2314 case D3DFVF_XYZRHW
: size
+= 4 * sizeof(FLOAT
); break;
2315 case D3DFVF_XYZB1
: size
+= 4 * sizeof(FLOAT
); break;
2316 case D3DFVF_XYZB2
: size
+= 5 * sizeof(FLOAT
); break;
2317 case D3DFVF_XYZB3
: size
+= 6 * sizeof(FLOAT
); break;
2318 case D3DFVF_XYZB4
: size
+= 7 * sizeof(FLOAT
); break;
2319 case D3DFVF_XYZB5
: size
+= 8 * sizeof(FLOAT
); break;
2320 case D3DFVF_XYZW
: size
+= 4 * sizeof(FLOAT
); break;
2323 for (i
= 0; i
< numTextures
; i
++)
2325 size
+= Get_TexCoord_Size_From_FVF(FVF
, i
) * sizeof(FLOAT
);
2331 /*************************************************************************
2332 * D3DXGetDeclVertexSize
2334 UINT WINAPI
D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9
*decl
, DWORD stream_idx
)
2336 const D3DVERTEXELEMENT9
*element
;
2339 TRACE("decl %p, stream_idx %u\n", decl
, stream_idx
);
2341 if (!decl
) return 0;
2343 for (element
= decl
; element
->Stream
!= 0xff; ++element
)
2347 if (element
->Stream
!= stream_idx
) continue;
2349 if (element
->Type
>= sizeof(d3dx_decltype_size
) / sizeof(*d3dx_decltype_size
))
2351 FIXME("Unhandled element type %#x, size will be incorrect.\n", element
->Type
);
2355 type_size
= d3dx_decltype_size
[element
->Type
];
2356 if (element
->Offset
+ type_size
> size
) size
= element
->Offset
+ type_size
;
2362 /*************************************************************************
2365 UINT WINAPI
D3DXGetDeclLength(const D3DVERTEXELEMENT9
*decl
)
2367 const D3DVERTEXELEMENT9
*element
;
2369 TRACE("decl %p\n", decl
);
2371 /* null decl results in exception on Windows XP */
2373 for (element
= decl
; element
->Stream
!= 0xff; ++element
);
2375 return element
- decl
;
2378 /*************************************************************************
2381 BOOL WINAPI
D3DXIntersectTri(CONST D3DXVECTOR3
*p0
, CONST D3DXVECTOR3
*p1
, CONST D3DXVECTOR3
*p2
, CONST D3DXVECTOR3
*praypos
, CONST D3DXVECTOR3
*praydir
, FLOAT
*pu
, FLOAT
*pv
, FLOAT
*pdist
)
2386 m
.u
.m
[0][0] = p1
->x
- p0
->x
;
2387 m
.u
.m
[1][0] = p2
->x
- p0
->x
;
2388 m
.u
.m
[2][0] = -praydir
->x
;
2390 m
.u
.m
[0][1] = p1
->y
- p0
->z
;
2391 m
.u
.m
[1][1] = p2
->y
- p0
->z
;
2392 m
.u
.m
[2][1] = -praydir
->y
;
2394 m
.u
.m
[0][2] = p1
->z
- p0
->z
;
2395 m
.u
.m
[1][2] = p2
->z
- p0
->z
;
2396 m
.u
.m
[2][2] = -praydir
->z
;
2403 vec
.x
= praypos
->x
- p0
->x
;
2404 vec
.y
= praypos
->y
- p0
->y
;
2405 vec
.z
= praypos
->z
- p0
->z
;
2408 if ( D3DXMatrixInverse(&m
, NULL
, &m
) )
2410 D3DXVec4Transform(&vec
, &vec
, &m
);
2411 if ( (vec
.x
>= 0.0f
) && (vec
.y
>= 0.0f
) && (vec
.x
+ vec
.y
<= 1.0f
) && (vec
.z
>= 0.0f
) )
2415 *pdist
= fabs( vec
.z
);
2423 /*************************************************************************
2424 * D3DXSphereBoundProbe
2426 BOOL WINAPI
D3DXSphereBoundProbe(CONST D3DXVECTOR3
*pcenter
, FLOAT radius
, CONST D3DXVECTOR3
*prayposition
, CONST D3DXVECTOR3
*praydirection
)
2428 D3DXVECTOR3 difference
;
2431 a
= D3DXVec3LengthSq(praydirection
);
2432 if (!D3DXVec3Subtract(&difference
, prayposition
, pcenter
)) return FALSE
;
2433 b
= D3DXVec3Dot(&difference
, praydirection
);
2434 c
= D3DXVec3LengthSq(&difference
) - radius
* radius
;
2437 if ( ( d
<= 0.0f
) || ( sqrt(d
) <= b
) ) return FALSE
;
2441 /*************************************************************************
2444 HRESULT WINAPI
D3DXCreateMesh(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2445 const D3DVERTEXELEMENT9
*declaration
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2449 IDirect3DVertexDeclaration9
*vertex_declaration
;
2450 UINT vertex_declaration_size
;
2452 IDirect3DVertexBuffer9
*vertex_buffer
;
2453 IDirect3DIndexBuffer9
*index_buffer
;
2454 DWORD
*attrib_buffer
;
2455 ID3DXMeshImpl
*object
;
2456 DWORD index_usage
= 0;
2457 D3DPOOL index_pool
= D3DPOOL_DEFAULT
;
2458 D3DFORMAT index_format
= D3DFMT_INDEX16
;
2459 DWORD vertex_usage
= 0;
2460 D3DPOOL vertex_pool
= D3DPOOL_DEFAULT
;
2463 TRACE("(%d, %d, %x, %p, %p, %p)\n", numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2465 if (numfaces
== 0 || numvertices
== 0 || declaration
== NULL
|| device
== NULL
|| mesh
== NULL
||
2466 /* D3DXMESH_VB_SHARE is for cloning, and D3DXMESH_USEHWONLY is for ConvertToBlendedMesh */
2467 (options
& (D3DXMESH_VB_SHARE
| D3DXMESH_USEHWONLY
| 0xfffe0000)))
2469 return D3DERR_INVALIDCALL
;
2471 for (i
= 0; declaration
[i
].Stream
!= 0xff; i
++)
2472 if (declaration
[i
].Stream
!= 0)
2473 return D3DERR_INVALIDCALL
;
2476 if (options
& D3DXMESH_32BIT
)
2477 index_format
= D3DFMT_INDEX32
;
2479 if (options
& D3DXMESH_DONOTCLIP
) {
2480 index_usage
|= D3DUSAGE_DONOTCLIP
;
2481 vertex_usage
|= D3DUSAGE_DONOTCLIP
;
2483 if (options
& D3DXMESH_POINTS
) {
2484 index_usage
|= D3DUSAGE_POINTS
;
2485 vertex_usage
|= D3DUSAGE_POINTS
;
2487 if (options
& D3DXMESH_RTPATCHES
) {
2488 index_usage
|= D3DUSAGE_RTPATCHES
;
2489 vertex_usage
|= D3DUSAGE_RTPATCHES
;
2491 if (options
& D3DXMESH_NPATCHES
) {
2492 index_usage
|= D3DUSAGE_NPATCHES
;
2493 vertex_usage
|= D3DUSAGE_NPATCHES
;
2496 if (options
& D3DXMESH_VB_SYSTEMMEM
)
2497 vertex_pool
= D3DPOOL_SYSTEMMEM
;
2498 else if (options
& D3DXMESH_VB_MANAGED
)
2499 vertex_pool
= D3DPOOL_MANAGED
;
2501 if (options
& D3DXMESH_VB_WRITEONLY
)
2502 vertex_usage
|= D3DUSAGE_WRITEONLY
;
2503 if (options
& D3DXMESH_VB_DYNAMIC
)
2504 vertex_usage
|= D3DUSAGE_DYNAMIC
;
2505 if (options
& D3DXMESH_VB_SOFTWAREPROCESSING
)
2506 vertex_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2508 if (options
& D3DXMESH_IB_SYSTEMMEM
)
2509 index_pool
= D3DPOOL_SYSTEMMEM
;
2510 else if (options
& D3DXMESH_IB_MANAGED
)
2511 index_pool
= D3DPOOL_MANAGED
;
2513 if (options
& D3DXMESH_IB_WRITEONLY
)
2514 index_usage
|= D3DUSAGE_WRITEONLY
;
2515 if (options
& D3DXMESH_IB_DYNAMIC
)
2516 index_usage
|= D3DUSAGE_DYNAMIC
;
2517 if (options
& D3DXMESH_IB_SOFTWAREPROCESSING
)
2518 index_usage
|= D3DUSAGE_SOFTWAREPROCESSING
;
2520 hr
= D3DXFVFFromDeclarator(declaration
, &fvf
);
2526 /* Create vertex declaration */
2527 hr
= IDirect3DDevice9_CreateVertexDeclaration(device
,
2529 &vertex_declaration
);
2532 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr
);
2535 vertex_declaration_size
= D3DXGetDeclVertexSize(declaration
, declaration
[0].Stream
);
2537 /* Create vertex buffer */
2538 hr
= IDirect3DDevice9_CreateVertexBuffer(device
,
2539 numvertices
* vertex_declaration_size
,
2547 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2548 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2552 /* Create index buffer */
2553 hr
= IDirect3DDevice9_CreateIndexBuffer(device
,
2554 numfaces
* 3 * ((index_format
== D3DFMT_INDEX16
) ? 2 : 4),
2562 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr
);
2563 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2564 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2568 attrib_buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, numfaces
* sizeof(*attrib_buffer
));
2569 object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(ID3DXMeshImpl
));
2570 if (object
== NULL
|| attrib_buffer
== NULL
)
2572 HeapFree(GetProcessHeap(), 0, object
);
2573 HeapFree(GetProcessHeap(), 0, attrib_buffer
);
2574 IDirect3DIndexBuffer9_Release(index_buffer
);
2575 IDirect3DVertexBuffer9_Release(vertex_buffer
);
2576 IDirect3DVertexDeclaration9_Release(vertex_declaration
);
2578 return E_OUTOFMEMORY
;
2580 object
->ID3DXMesh_iface
.lpVtbl
= &D3DXMesh_Vtbl
;
2583 object
->numfaces
= numfaces
;
2584 object
->numvertices
= numvertices
;
2585 object
->options
= options
;
2587 object
->device
= device
;
2588 IDirect3DDevice9_AddRef(device
);
2590 copy_declaration(object
->cached_declaration
, declaration
, num_elem
);
2591 object
->vertex_declaration
= vertex_declaration
;
2592 object
->vertex_declaration_size
= vertex_declaration_size
;
2593 object
->num_elem
= num_elem
;
2594 object
->vertex_buffer
= vertex_buffer
;
2595 object
->index_buffer
= index_buffer
;
2596 object
->attrib_buffer
= attrib_buffer
;
2598 *mesh
= &object
->ID3DXMesh_iface
;
2603 /*************************************************************************
2606 HRESULT WINAPI
D3DXCreateMeshFVF(DWORD numfaces
, DWORD numvertices
, DWORD options
,
2607 DWORD fvf
, struct IDirect3DDevice9
*device
, struct ID3DXMesh
**mesh
)
2610 D3DVERTEXELEMENT9 declaration
[MAX_FVF_DECL_SIZE
];
2612 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces
, numvertices
, options
, fvf
, device
, mesh
);
2614 hr
= D3DXDeclaratorFromFVF(fvf
, declaration
);
2615 if (FAILED(hr
)) return hr
;
2617 return D3DXCreateMesh(numfaces
, numvertices
, options
, declaration
, device
, mesh
);
2623 DWORD num_poly_faces
;
2624 DWORD num_tri_faces
;
2625 D3DXVECTOR3
*vertices
;
2626 DWORD
*num_tri_per_face
;
2631 /* optional mesh data */
2634 D3DXVECTOR3
*normals
;
2635 DWORD
*normal_indices
;
2637 D3DXVECTOR2
*tex_coords
;
2639 DWORD
*vertex_colors
;
2641 DWORD num_materials
;
2642 D3DXMATERIAL
*materials
;
2643 DWORD
*material_indices
;
2645 struct ID3DXSkinInfo
*skin_info
;
2649 static HRESULT
parse_texture_filename(ID3DXFileData
*filedata
, LPSTR
*filename_out
)
2655 char *filename
= NULL
;
2657 /* template TextureFilename {
2662 HeapFree(GetProcessHeap(), 0, *filename_out
);
2663 *filename_out
= NULL
;
2665 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2666 if (FAILED(hr
)) return hr
;
2668 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
2669 if (data_size
< sizeof(LPSTR
)) {
2670 WARN("truncated data (%lu bytes)\n", data_size
);
2671 filedata
->lpVtbl
->Unlock(filedata
);
2674 filename_in
= *(LPSTR
*)data
;
2676 filename
= HeapAlloc(GetProcessHeap(), 0, strlen(filename_in
) + 1);
2678 filedata
->lpVtbl
->Unlock(filedata
);
2679 return E_OUTOFMEMORY
;
2682 strcpy(filename
, filename_in
);
2683 *filename_out
= filename
;
2685 filedata
->lpVtbl
->Unlock(filedata
);
2690 static HRESULT
parse_material(ID3DXFileData
*filedata
, D3DXMATERIAL
*material
)
2696 ID3DXFileData
*child
;
2700 material
->pTextureFilename
= NULL
;
2702 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2703 if (FAILED(hr
)) return hr
;
2706 * template ColorRGBA {
2712 * template ColorRGB {
2717 * template Material {
2718 * ColorRGBA faceColor;
2720 * ColorRGB specularColor;
2721 * ColorRGB emissiveColor;
2725 if (data_size
!= sizeof(FLOAT
) * 11) {
2726 WARN("incorrect data size (%ld bytes)\n", data_size
);
2727 filedata
->lpVtbl
->Unlock(filedata
);
2731 memcpy(&material
->MatD3D
.Diffuse
, data
, sizeof(D3DCOLORVALUE
));
2732 data
+= sizeof(D3DCOLORVALUE
);
2733 material
->MatD3D
.Power
= *(FLOAT
*)data
;
2734 data
+= sizeof(FLOAT
);
2735 memcpy(&material
->MatD3D
.Specular
, data
, sizeof(FLOAT
) * 3);
2736 material
->MatD3D
.Specular
.a
= 1.0f
;
2737 data
+= 3 * sizeof(FLOAT
);
2738 memcpy(&material
->MatD3D
.Emissive
, data
, sizeof(FLOAT
) * 3);
2739 material
->MatD3D
.Emissive
.a
= 1.0f
;
2740 material
->MatD3D
.Ambient
.r
= 0.0f
;
2741 material
->MatD3D
.Ambient
.g
= 0.0f
;
2742 material
->MatD3D
.Ambient
.b
= 0.0f
;
2743 material
->MatD3D
.Ambient
.a
= 1.0f
;
2745 filedata
->lpVtbl
->Unlock(filedata
);
2747 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
2751 for (i
= 0; i
< nb_children
; i
++)
2753 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
2756 hr
= child
->lpVtbl
->GetType(child
, &type
);
2760 if (IsEqualGUID(&type
, &TID_D3DRMTextureFilename
)) {
2761 hr
= parse_texture_filename(child
, &material
->pTextureFilename
);
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
;
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 if (num_materials
!= mesh
->num_materials
) {
2873 WARN("only %u of %u materials defined\n", num_materials
, mesh
->num_materials
);
2878 filedata
->lpVtbl
->Unlock(filedata
);
2882 static HRESULT
parse_texture_coords(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2888 HeapFree(GetProcessHeap(), 0, mesh
->tex_coords
);
2889 mesh
->tex_coords
= NULL
;
2891 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2892 if (FAILED(hr
)) return hr
;
2894 /* template Coords2d {
2898 * template MeshTextureCoords {
2899 * DWORD nTextureCoords;
2900 * array Coords2d textureCoords[nTextureCoords];
2906 if (data_size
< sizeof(DWORD
)) {
2907 WARN("truncated data (%ld bytes)\n", data_size
);
2910 if (*(DWORD
*)data
!= mesh
->num_vertices
) {
2911 WARN("number of texture coordinates (%u) doesn't match number of vertices (%u)\n",
2912 *(DWORD
*)data
, mesh
->num_vertices
);
2915 data
+= sizeof(DWORD
);
2916 if (data_size
< sizeof(DWORD
) + mesh
->num_vertices
* sizeof(*mesh
->tex_coords
)) {
2917 WARN("truncated data (%ld bytes)\n", data_size
);
2921 mesh
->tex_coords
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2922 if (!mesh
->tex_coords
) {
2926 memcpy(mesh
->tex_coords
, data
, mesh
->num_vertices
* sizeof(*mesh
->tex_coords
));
2928 mesh
->fvf
|= D3DFVF_TEX1
;
2933 filedata
->lpVtbl
->Unlock(filedata
);
2937 static HRESULT
parse_vertex_colors(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
2945 HeapFree(GetProcessHeap(), 0, mesh
->vertex_colors
);
2946 mesh
->vertex_colors
= NULL
;
2948 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
2949 if (FAILED(hr
)) return hr
;
2951 /* template IndexedColor {
2953 * ColorRGBA indexColor;
2955 * template MeshVertexColors {
2956 * DWORD nVertexColors;
2957 * array IndexedColor vertexColors[nVertexColors];
2963 if (data_size
< sizeof(DWORD
)) {
2964 WARN("truncated data (%ld bytes)\n", data_size
);
2967 num_colors
= *(DWORD
*)data
;
2968 data
+= sizeof(DWORD
);
2969 if (data_size
< sizeof(DWORD
) + num_colors
* (sizeof(DWORD
) + sizeof(D3DCOLORVALUE
))) {
2970 WARN("truncated data (%ld bytes)\n", data_size
);
2974 mesh
->vertex_colors
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_vertices
* sizeof(DWORD
));
2975 if (!mesh
->vertex_colors
) {
2980 for (i
= 0; i
< mesh
->num_vertices
; i
++)
2981 mesh
->vertex_colors
[i
] = D3DCOLOR_ARGB(0, 0xff, 0xff, 0xff);
2982 for (i
= 0; i
< num_colors
; i
++)
2984 D3DCOLORVALUE color
;
2985 DWORD index
= *(DWORD
*)data
;
2986 data
+= sizeof(DWORD
);
2987 if (index
>= mesh
->num_vertices
) {
2988 WARN("vertex color %u references undefined vertex %u (only %u vertices)\n",
2989 i
, index
, mesh
->num_vertices
);
2992 memcpy(&color
, data
, sizeof(color
));
2993 data
+= sizeof(color
);
2994 color
.r
= min(1.0f
, max(0.0f
, color
.r
));
2995 color
.g
= min(1.0f
, max(0.0f
, color
.g
));
2996 color
.b
= min(1.0f
, max(0.0f
, color
.b
));
2997 color
.a
= min(1.0f
, max(0.0f
, color
.a
));
2998 mesh
->vertex_colors
[index
] = D3DCOLOR_ARGB((BYTE
)(color
.a
* 255.0f
+ 0.5f
),
2999 (BYTE
)(color
.r
* 255.0f
+ 0.5f
),
3000 (BYTE
)(color
.g
* 255.0f
+ 0.5f
),
3001 (BYTE
)(color
.b
* 255.0f
+ 0.5f
));
3004 mesh
->fvf
|= D3DFVF_DIFFUSE
;
3009 filedata
->lpVtbl
->Unlock(filedata
);
3013 static HRESULT
parse_normals(ID3DXFileData
*filedata
, struct mesh_data
*mesh
)
3018 DWORD
*index_out_ptr
;
3020 DWORD num_face_indices
= mesh
->num_poly_faces
* 2 + mesh
->num_tri_faces
;
3022 HeapFree(GetProcessHeap(), 0, mesh
->normals
);
3023 mesh
->num_normals
= 0;
3024 mesh
->normals
= NULL
;
3025 mesh
->normal_indices
= NULL
;
3026 mesh
->fvf
|= D3DFVF_NORMAL
;
3028 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3029 if (FAILED(hr
)) return hr
;
3031 /* template Vector {
3036 * template MeshFace {
3037 * DWORD nFaceVertexIndices;
3038 * array DWORD faceVertexIndices[nFaceVertexIndices];
3040 * template MeshNormals {
3042 * array Vector normals[nNormals];
3043 * DWORD nFaceNormals;
3044 * array MeshFace faceNormals[nFaceNormals];
3050 if (data_size
< sizeof(DWORD
) * 2) {
3051 WARN("truncated data (%ld bytes)\n", data_size
);
3054 mesh
->num_normals
= *(DWORD
*)data
;
3055 data
+= sizeof(DWORD
);
3056 if (data_size
< sizeof(DWORD
) * 2 + mesh
->num_normals
* sizeof(D3DXVECTOR3
) +
3057 num_face_indices
* sizeof(DWORD
)) {
3058 WARN("truncated data (%ld bytes)\n", data_size
);
3062 mesh
->normals
= HeapAlloc(GetProcessHeap(), 0, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3063 mesh
->normal_indices
= HeapAlloc(GetProcessHeap(), 0, num_face_indices
* sizeof(DWORD
));
3064 if (!mesh
->normals
|| !mesh
->normal_indices
) {
3069 memcpy(mesh
->normals
, data
, mesh
->num_normals
* sizeof(D3DXVECTOR3
));
3070 data
+= mesh
->num_normals
* sizeof(D3DXVECTOR3
);
3071 for (i
= 0; i
< mesh
->num_normals
; i
++)
3072 D3DXVec3Normalize(&mesh
->normals
[i
], &mesh
->normals
[i
]);
3074 if (*(DWORD
*)data
!= mesh
->num_poly_faces
) {
3075 WARN("number of face normals (%u) doesn't match number of faces (%u)\n",
3076 *(DWORD
*)data
, mesh
->num_poly_faces
);
3079 data
+= sizeof(DWORD
);
3080 index_out_ptr
= mesh
->normal_indices
;
3081 for (i
= 0; i
< mesh
->num_poly_faces
; i
++)
3084 DWORD count
= *(DWORD
*)data
;
3085 if (count
!= mesh
->num_tri_per_face
[i
] + 2) {
3086 WARN("face %u: number of normals (%u) doesn't match number of vertices (%u)\n",
3087 i
, count
, mesh
->num_tri_per_face
[i
] + 2);
3090 data
+= sizeof(DWORD
);
3092 for (j
= 0; j
< count
; j
++) {
3093 DWORD normal_index
= *(DWORD
*)data
;
3094 if (normal_index
>= mesh
->num_normals
) {
3095 WARN("face %u, normal index %u: reference to undefined normal %u (only %u normals)\n",
3096 i
, j
, normal_index
, mesh
->num_normals
);
3099 *index_out_ptr
++ = normal_index
;
3100 data
+= sizeof(DWORD
);
3107 filedata
->lpVtbl
->Unlock(filedata
);
3111 static HRESULT
parse_skin_mesh_info(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD index
)
3117 TRACE("(%p, %p, %u)\n", filedata
, mesh_data
, index
);
3119 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3120 if (FAILED(hr
)) return hr
;
3124 if (!mesh_data
->skin_info
) {
3125 if (data_size
< sizeof(WORD
) * 3) {
3126 WARN("truncated data (%ld bytes)\n", data_size
);
3129 /* Skip nMaxSkinWeightsPerVertex and nMaxSkinWeightsPerFace */
3130 data
+= 2 * sizeof(WORD
);
3131 mesh_data
->nb_bones
= *(WORD
*)data
;
3132 hr
= D3DXCreateSkinInfoFVF(mesh_data
->num_vertices
, mesh_data
->fvf
, mesh_data
->nb_bones
, &mesh_data
->skin_info
);
3135 DWORD nb_influences
;
3137 /* FIXME: String must be retrieved directly instead of through a pointer once ID3DXFILE is fixed */
3138 name
= *(const char**)data
;
3139 data
+= sizeof(char*);
3141 nb_influences
= *(DWORD
*)data
;
3142 data
+= sizeof(DWORD
);
3144 if (data_size
< (sizeof(char*) + sizeof(DWORD
) + nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
)) + 16 * sizeof(FLOAT
))) {
3145 WARN("truncated data (%ld bytes)\n", data_size
);
3149 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneName(mesh_data
->skin_info
, index
, name
);
3151 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneInfluence(mesh_data
->skin_info
, index
, nb_influences
,
3152 (const DWORD
*)data
, (const FLOAT
*)(data
+ nb_influences
* sizeof(DWORD
)));
3154 hr
= mesh_data
->skin_info
->lpVtbl
->SetBoneOffsetMatrix(mesh_data
->skin_info
, index
,
3155 (const D3DMATRIX
*)(data
+ nb_influences
* (sizeof(DWORD
) + sizeof(FLOAT
))));
3159 filedata
->lpVtbl
->Unlock(filedata
);
3163 /* for provide_flags parameters */
3164 #define PROVIDE_MATERIALS 0x1
3165 #define PROVIDE_SKININFO 0x2
3166 #define PROVIDE_ADJACENCY 0x4
3168 static HRESULT
parse_mesh(ID3DXFileData
*filedata
, struct mesh_data
*mesh_data
, DWORD provide_flags
)
3172 const BYTE
*data
, *in_ptr
;
3173 DWORD
*index_out_ptr
;
3175 ID3DXFileData
*child
;
3178 DWORD nb_skin_weigths_info
= 0;
3183 * array Vector vertices[nVertices];
3185 * array MeshFace faces[nFaces];
3190 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3191 if (FAILED(hr
)) return hr
;
3196 if (data_size
< sizeof(DWORD
) * 2) {
3197 WARN("truncated data (%ld bytes)\n", data_size
);
3200 mesh_data
->num_vertices
= *(DWORD
*)in_ptr
;
3201 if (data_size
< sizeof(DWORD
) * 2 + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
)) {
3202 WARN("truncated data (%ld bytes)\n", data_size
);
3205 in_ptr
+= sizeof(DWORD
) + mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
);
3207 mesh_data
->num_poly_faces
= *(DWORD
*)in_ptr
;
3208 in_ptr
+= sizeof(DWORD
);
3210 mesh_data
->num_tri_faces
= 0;
3211 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3213 DWORD num_poly_vertices
;
3216 if (data_size
- (in_ptr
- data
) < sizeof(DWORD
)) {
3217 WARN("truncated data (%ld bytes)\n", data_size
);
3220 num_poly_vertices
= *(DWORD
*)in_ptr
;
3221 in_ptr
+= sizeof(DWORD
);
3222 if (data_size
- (in_ptr
- data
) < num_poly_vertices
* sizeof(DWORD
)) {
3223 WARN("truncated data (%ld bytes)\n", data_size
);
3226 if (num_poly_vertices
< 3) {
3227 WARN("face %u has only %u vertices\n", i
, num_poly_vertices
);
3230 for (j
= 0; j
< num_poly_vertices
; j
++) {
3231 if (*(DWORD
*)in_ptr
>= mesh_data
->num_vertices
) {
3232 WARN("face %u, index %u: undefined vertex %u (only %u vertices)\n",
3233 i
, j
, *(DWORD
*)in_ptr
, mesh_data
->num_vertices
);
3236 in_ptr
+= sizeof(DWORD
);
3238 mesh_data
->num_tri_faces
+= num_poly_vertices
- 2;
3241 mesh_data
->fvf
= D3DFVF_XYZ
;
3243 mesh_data
->vertices
= HeapAlloc(GetProcessHeap(), 0,
3244 mesh_data
->num_vertices
* sizeof(*mesh_data
->vertices
));
3245 mesh_data
->num_tri_per_face
= HeapAlloc(GetProcessHeap(), 0,
3246 mesh_data
->num_poly_faces
* sizeof(*mesh_data
->num_tri_per_face
));
3247 mesh_data
->indices
= HeapAlloc(GetProcessHeap(), 0,
3248 (mesh_data
->num_tri_faces
+ mesh_data
->num_poly_faces
* 2) * sizeof(*mesh_data
->indices
));
3249 if (!mesh_data
->vertices
|| !mesh_data
->num_tri_per_face
|| !mesh_data
->indices
) {
3254 in_ptr
= data
+ sizeof(DWORD
);
3255 memcpy(mesh_data
->vertices
, in_ptr
, mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
));
3256 in_ptr
+= mesh_data
->num_vertices
* sizeof(D3DXVECTOR3
) + sizeof(DWORD
);
3258 index_out_ptr
= mesh_data
->indices
;
3259 for (i
= 0; i
< mesh_data
->num_poly_faces
; i
++)
3263 count
= *(DWORD
*)in_ptr
;
3264 in_ptr
+= sizeof(DWORD
);
3265 mesh_data
->num_tri_per_face
[i
] = count
- 2;
3268 *index_out_ptr
++ = *(DWORD
*)in_ptr
;
3269 in_ptr
+= sizeof(DWORD
);
3273 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3277 for (i
= 0; i
< nb_children
; i
++)
3279 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3282 hr
= child
->lpVtbl
->GetType(child
, &type
);
3286 if (IsEqualGUID(&type
, &TID_D3DRMMeshNormals
)) {
3287 hr
= parse_normals(child
, mesh_data
);
3288 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshVertexColors
)) {
3289 hr
= parse_vertex_colors(child
, mesh_data
);
3290 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshTextureCoords
)) {
3291 hr
= parse_texture_coords(child
, mesh_data
);
3292 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3295 } else if (IsEqualGUID(&type
, &TID_D3DRMMeshMaterialList
) &&
3296 (provide_flags
& PROVIDE_MATERIALS
))
3298 hr
= parse_material_list(child
, mesh_data
);
3299 } else if (provide_flags
& PROVIDE_SKININFO
) {
3300 if (IsEqualGUID(&type
, &DXFILEOBJ_XSkinMeshHeader
)) {
3301 if (mesh_data
->skin_info
) {
3302 WARN("Skin mesh header already encountered\n");
3306 hr
= parse_skin_mesh_info(child
, mesh_data
, 0);
3309 } else if (IsEqualGUID(&type
, &DXFILEOBJ_SkinWeights
)) {
3310 if (!mesh_data
->skin_info
) {
3311 WARN("Skin weigths found but skin mesh header not encountered yet\n");
3315 hr
= parse_skin_mesh_info(child
, mesh_data
, nb_skin_weigths_info
);
3318 nb_skin_weigths_info
++;
3325 if (mesh_data
->skin_info
&& (nb_skin_weigths_info
!= mesh_data
->nb_bones
)) {
3326 WARN("Mismatch between nb skin weights info %u encountered and nb bones %u from skin mesh header\n",
3327 nb_skin_weigths_info
, mesh_data
->nb_bones
);
3335 filedata
->lpVtbl
->Unlock(filedata
);
3339 static HRESULT
generate_effects(ID3DXBuffer
*materials
, DWORD num_materials
,
3340 ID3DXBuffer
**effects
)
3343 D3DXEFFECTINSTANCE
*effect_ptr
;
3345 const D3DXMATERIAL
*material_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3346 static const struct {
3347 const char *param_name
;
3351 } material_effects
[] = {
3352 #define EFFECT_TABLE_ENTRY(str, field) \
3353 {str, sizeof(str), sizeof(material_ptr->MatD3D.field), offsetof(D3DXMATERIAL, MatD3D.field)}
3354 EFFECT_TABLE_ENTRY("Diffuse", Diffuse
),
3355 EFFECT_TABLE_ENTRY("Power", Power
),
3356 EFFECT_TABLE_ENTRY("Specular", Specular
),
3357 EFFECT_TABLE_ENTRY("Emissive", Emissive
),
3358 EFFECT_TABLE_ENTRY("Ambient", Ambient
),
3359 #undef EFFECT_TABLE_ENTRY
3361 static const char texture_paramname
[] = "Texture0@Name";
3365 /* effects buffer layout:
3367 * D3DXEFFECTINSTANCE effects[num_materials];
3368 * for (effect in effects)
3370 * D3DXEFFECTDEFAULT defaults[effect.NumDefaults];
3371 * for (default in defaults)
3373 * *default.pParamName;
3378 buffer_size
= sizeof(D3DXEFFECTINSTANCE
);
3379 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
) * ARRAY_SIZE(material_effects
);
3380 for (i
= 0; i
< ARRAY_SIZE(material_effects
); i
++) {
3381 buffer_size
+= material_effects
[i
].name_size
;
3382 buffer_size
+= material_effects
[i
].num_bytes
;
3384 buffer_size
*= num_materials
;
3385 for (i
= 0; i
< num_materials
; i
++) {
3386 if (material_ptr
[i
].pTextureFilename
) {
3387 buffer_size
+= sizeof(D3DXEFFECTDEFAULT
);
3388 buffer_size
+= sizeof(texture_paramname
);
3389 buffer_size
+= strlen(material_ptr
[i
].pTextureFilename
) + 1;
3393 hr
= D3DXCreateBuffer(buffer_size
, effects
);
3394 if (FAILED(hr
)) return hr
;
3395 effect_ptr
= ID3DXBuffer_GetBufferPointer(*effects
);
3396 out_ptr
= (BYTE
*)(effect_ptr
+ num_materials
);
3398 for (i
= 0; i
< num_materials
; i
++)
3401 D3DXEFFECTDEFAULT
*defaults
= (D3DXEFFECTDEFAULT
*)out_ptr
;
3403 effect_ptr
->pDefaults
= defaults
;
3404 effect_ptr
->NumDefaults
= material_ptr
->pTextureFilename
? 6 : 5;
3405 out_ptr
= (BYTE
*)(effect_ptr
->pDefaults
+ effect_ptr
->NumDefaults
);
3407 for (j
= 0; j
< ARRAY_SIZE(material_effects
); j
++)
3409 defaults
->pParamName
= (LPSTR
)out_ptr
;
3410 strcpy(defaults
->pParamName
, material_effects
[j
].param_name
);
3411 defaults
->pValue
= defaults
->pParamName
+ material_effects
[j
].name_size
;
3412 defaults
->Type
= D3DXEDT_FLOATS
;
3413 defaults
->NumBytes
= material_effects
[j
].num_bytes
;
3414 memcpy(defaults
->pValue
, (BYTE
*)material_ptr
+ material_effects
[j
].value_offset
, defaults
->NumBytes
);
3415 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3419 if (material_ptr
->pTextureFilename
) {
3420 defaults
->pParamName
= (LPSTR
)out_ptr
;
3421 strcpy(defaults
->pParamName
, texture_paramname
);
3422 defaults
->pValue
= defaults
->pParamName
+ sizeof(texture_paramname
);
3423 defaults
->Type
= D3DXEDT_STRING
;
3424 defaults
->NumBytes
= strlen(material_ptr
->pTextureFilename
) + 1;
3425 strcpy(defaults
->pValue
, material_ptr
->pTextureFilename
);
3426 out_ptr
= (BYTE
*)defaults
->pValue
+ defaults
->NumBytes
;
3431 assert(out_ptr
- (BYTE
*)ID3DXBuffer_GetBufferPointer(*effects
) == buffer_size
);
3436 HRESULT WINAPI
D3DXLoadSkinMeshFromXof(struct ID3DXFileData
*filedata
, DWORD options
,
3437 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
3438 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXSkinInfo
**skin_info_out
,
3439 struct ID3DXMesh
**mesh_out
)
3442 DWORD
*index_in_ptr
;
3443 struct mesh_data mesh_data
;
3444 DWORD total_vertices
;
3445 ID3DXMesh
*d3dxmesh
= NULL
;
3446 ID3DXBuffer
*adjacency
= NULL
;
3447 ID3DXBuffer
*materials
= NULL
;
3448 ID3DXBuffer
*effects
= NULL
;
3449 struct vertex_duplication
{
3452 } *duplications
= NULL
;
3454 void *vertices
= NULL
;
3455 void *indices
= NULL
;
3457 DWORD provide_flags
= 0;
3459 TRACE("(%p, %x, %p, %p, %p, %p, %p, %p, %p)\n", filedata
, options
, device
, adjacency_out
, materials_out
,
3460 effects_out
, num_materials_out
, skin_info_out
, mesh_out
);
3462 ZeroMemory(&mesh_data
, sizeof(mesh_data
));
3464 if (num_materials_out
|| materials_out
|| effects_out
)
3465 provide_flags
|= PROVIDE_MATERIALS
;
3467 provide_flags
|= PROVIDE_SKININFO
;
3469 hr
= parse_mesh(filedata
, &mesh_data
, provide_flags
);
3470 if (FAILED(hr
)) goto cleanup
;
3472 total_vertices
= mesh_data
.num_vertices
;
3473 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3474 /* duplicate vertices with multiple normals */
3475 DWORD num_face_indices
= mesh_data
.num_poly_faces
* 2 + mesh_data
.num_tri_faces
;
3476 duplications
= HeapAlloc(GetProcessHeap(), 0, (mesh_data
.num_vertices
+ num_face_indices
) * sizeof(*duplications
));
3477 if (!duplications
) {
3481 for (i
= 0; i
< total_vertices
; i
++)
3483 duplications
[i
].normal_index
= -1;
3484 list_init(&duplications
[i
].entry
);
3486 for (i
= 0; i
< num_face_indices
; i
++) {
3487 DWORD vertex_index
= mesh_data
.indices
[i
];
3488 DWORD normal_index
= mesh_data
.normal_indices
[i
];
3489 struct vertex_duplication
*dup_ptr
= &duplications
[vertex_index
];
3491 if (dup_ptr
->normal_index
== -1) {
3492 dup_ptr
->normal_index
= normal_index
;
3494 D3DXVECTOR3
*new_normal
= &mesh_data
.normals
[normal_index
];
3495 struct list
*dup_list
= &dup_ptr
->entry
;
3497 D3DXVECTOR3
*cur_normal
= &mesh_data
.normals
[dup_ptr
->normal_index
];
3498 if (new_normal
->x
== cur_normal
->x
&&
3499 new_normal
->y
== cur_normal
->y
&&
3500 new_normal
->z
== cur_normal
->z
)
3502 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3504 } else if (!list_next(dup_list
, &dup_ptr
->entry
)) {
3505 dup_ptr
= &duplications
[total_vertices
++];
3506 dup_ptr
->normal_index
= normal_index
;
3507 list_add_tail(dup_list
, &dup_ptr
->entry
);
3508 mesh_data
.indices
[i
] = dup_ptr
- duplications
;
3511 dup_ptr
= LIST_ENTRY(list_next(dup_list
, &dup_ptr
->entry
),
3512 struct vertex_duplication
, entry
);
3519 hr
= D3DXCreateMeshFVF(mesh_data
.num_tri_faces
, total_vertices
, options
, mesh_data
.fvf
, device
, &d3dxmesh
);
3520 if (FAILED(hr
)) goto cleanup
;
3522 hr
= d3dxmesh
->lpVtbl
->LockVertexBuffer(d3dxmesh
, 0, &vertices
);
3523 if (FAILED(hr
)) goto cleanup
;
3526 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3527 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.vertices
[i
];
3528 out_ptr
+= sizeof(D3DXVECTOR3
);
3529 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3530 if (duplications
[i
].normal_index
== -1)
3531 ZeroMemory(out_ptr
, sizeof(D3DXVECTOR3
));
3533 *(D3DXVECTOR3
*)out_ptr
= mesh_data
.normals
[duplications
[i
].normal_index
];
3534 out_ptr
+= sizeof(D3DXVECTOR3
);
3536 if (mesh_data
.fvf
& D3DFVF_DIFFUSE
) {
3537 *(DWORD
*)out_ptr
= mesh_data
.vertex_colors
[i
];
3538 out_ptr
+= sizeof(DWORD
);
3540 if (mesh_data
.fvf
& D3DFVF_TEX1
) {
3541 *(D3DXVECTOR2
*)out_ptr
= mesh_data
.tex_coords
[i
];
3542 out_ptr
+= sizeof(D3DXVECTOR2
);
3545 if (mesh_data
.fvf
& D3DFVF_NORMAL
) {
3546 DWORD vertex_size
= D3DXGetFVFVertexSize(mesh_data
.fvf
);
3548 for (i
= 0; i
< mesh_data
.num_vertices
; i
++) {
3549 struct vertex_duplication
*dup_ptr
;
3550 LIST_FOR_EACH_ENTRY(dup_ptr
, &duplications
[i
].entry
, struct vertex_duplication
, entry
)
3552 int j
= dup_ptr
- duplications
;
3553 BYTE
*dest_vertex
= (BYTE
*)vertices
+ j
* vertex_size
;
3555 memcpy(dest_vertex
, out_ptr
, vertex_size
);
3556 dest_vertex
+= sizeof(D3DXVECTOR3
);
3557 *(D3DXVECTOR3
*)dest_vertex
= mesh_data
.normals
[dup_ptr
->normal_index
];
3559 out_ptr
+= vertex_size
;
3562 d3dxmesh
->lpVtbl
->UnlockVertexBuffer(d3dxmesh
);
3564 hr
= d3dxmesh
->lpVtbl
->LockIndexBuffer(d3dxmesh
, 0, &indices
);
3565 if (FAILED(hr
)) goto cleanup
;
3567 index_in_ptr
= mesh_data
.indices
;
3568 #define FILL_INDEX_BUFFER(indices_var) \
3569 for (i = 0; i < mesh_data.num_poly_faces; i++) \
3571 DWORD count = mesh_data.num_tri_per_face[i]; \
3572 WORD first_index = *index_in_ptr++; \
3574 *indices_var++ = first_index; \
3575 *indices_var++ = *index_in_ptr; \
3577 *indices_var++ = *index_in_ptr; \
3581 if (options
& D3DXMESH_32BIT
) {
3582 DWORD
*dword_indices
= indices
;
3583 FILL_INDEX_BUFFER(dword_indices
)
3585 WORD
*word_indices
= indices
;
3586 FILL_INDEX_BUFFER(word_indices
)
3588 #undef FILL_INDEX_BUFFER
3589 d3dxmesh
->lpVtbl
->UnlockIndexBuffer(d3dxmesh
);
3591 if (mesh_data
.material_indices
) {
3592 DWORD
*attrib_buffer
= NULL
;
3593 hr
= d3dxmesh
->lpVtbl
->LockAttributeBuffer(d3dxmesh
, 0, &attrib_buffer
);
3594 if (FAILED(hr
)) goto cleanup
;
3595 for (i
= 0; i
< mesh_data
.num_poly_faces
; i
++)
3597 DWORD count
= mesh_data
.num_tri_per_face
[i
];
3599 *attrib_buffer
++ = mesh_data
.material_indices
[i
];
3601 d3dxmesh
->lpVtbl
->UnlockAttributeBuffer(d3dxmesh
);
3603 hr
= d3dxmesh
->lpVtbl
->OptimizeInplace(d3dxmesh
,
3604 D3DXMESHOPT_ATTRSORT
| D3DXMESHOPT_IGNOREVERTS
| D3DXMESHOPT_DONOTSPLIT
,
3605 NULL
, NULL
, NULL
, NULL
);
3606 if (FAILED(hr
)) goto cleanup
;
3609 if (mesh_data
.num_materials
&& (materials_out
|| effects_out
)) {
3610 DWORD buffer_size
= mesh_data
.num_materials
* sizeof(D3DXMATERIAL
);
3611 char *strings_out_ptr
;
3612 D3DXMATERIAL
*materials_ptr
;
3614 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3615 if (mesh_data
.materials
[i
].pTextureFilename
)
3616 buffer_size
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3619 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
3620 if (FAILED(hr
)) goto cleanup
;
3622 materials_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
3623 memcpy(materials_ptr
, mesh_data
.materials
, mesh_data
.num_materials
* sizeof(D3DXMATERIAL
));
3624 strings_out_ptr
= (char*)(materials_ptr
+ mesh_data
.num_materials
);
3625 for (i
= 0; i
< mesh_data
.num_materials
; i
++) {
3626 if (materials_ptr
[i
].pTextureFilename
) {
3627 strcpy(strings_out_ptr
, mesh_data
.materials
[i
].pTextureFilename
);
3628 materials_ptr
[i
].pTextureFilename
= strings_out_ptr
;
3629 strings_out_ptr
+= strlen(mesh_data
.materials
[i
].pTextureFilename
) + 1;
3634 if (mesh_data
.num_materials
&& effects_out
) {
3635 hr
= generate_effects(materials
, mesh_data
.num_materials
, &effects
);
3636 if (FAILED(hr
)) goto cleanup
;
3638 if (!materials_out
) {
3639 ID3DXBuffer_Release(materials
);
3644 if (adjacency_out
) {
3645 hr
= D3DXCreateBuffer(mesh_data
.num_tri_faces
* 3 * sizeof(DWORD
), &adjacency
);
3646 if (FAILED(hr
)) goto cleanup
;
3647 hr
= d3dxmesh
->lpVtbl
->GenerateAdjacency(d3dxmesh
, 0.0f
, ID3DXBuffer_GetBufferPointer(adjacency
));
3648 if (FAILED(hr
)) goto cleanup
;
3651 *mesh_out
= d3dxmesh
;
3652 if (adjacency_out
) *adjacency_out
= adjacency
;
3653 if (num_materials_out
) *num_materials_out
= mesh_data
.num_materials
;
3654 if (materials_out
) *materials_out
= materials
;
3655 if (effects_out
) *effects_out
= effects
;
3656 if (skin_info_out
) *skin_info_out
= mesh_data
.skin_info
;
3661 if (d3dxmesh
) IUnknown_Release(d3dxmesh
);
3662 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3663 if (materials
) ID3DXBuffer_Release(materials
);
3664 if (effects
) ID3DXBuffer_Release(effects
);
3665 if (mesh_data
.skin_info
) mesh_data
.skin_info
->lpVtbl
->Release(mesh_data
.skin_info
);
3666 if (skin_info_out
) *skin_info_out
= NULL
;
3668 HeapFree(GetProcessHeap(), 0, mesh_data
.vertices
);
3669 HeapFree(GetProcessHeap(), 0, mesh_data
.num_tri_per_face
);
3670 HeapFree(GetProcessHeap(), 0, mesh_data
.indices
);
3671 HeapFree(GetProcessHeap(), 0, mesh_data
.normals
);
3672 HeapFree(GetProcessHeap(), 0, mesh_data
.normal_indices
);
3673 destroy_materials(&mesh_data
);
3674 HeapFree(GetProcessHeap(), 0, mesh_data
.tex_coords
);
3675 HeapFree(GetProcessHeap(), 0, mesh_data
.vertex_colors
);
3676 HeapFree(GetProcessHeap(), 0, duplications
);
3680 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3681 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3682 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3688 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
3689 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3692 return D3DERR_INVALIDCALL
;
3694 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
3695 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
3696 if (!filenameW
) return E_OUTOFMEMORY
;
3697 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
3699 hr
= D3DXLoadMeshHierarchyFromXW(filenameW
, options
, device
,
3700 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3701 HeapFree(GetProcessHeap(), 0, filenameW
);
3706 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
3707 struct ID3DXAllocateHierarchy
*alloc_hier
, struct ID3DXLoadUserData
*load_user_data
,
3708 D3DXFRAME
**frame_hierarchy
, struct ID3DXAnimationController
**anim_controller
)
3714 TRACE("(%s, %x, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
3715 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3718 return D3DERR_INVALIDCALL
;
3720 hr
= map_view_of_file(filename
, &buffer
, &size
);
3722 return D3DXERR_INVALIDDATA
;
3724 hr
= D3DXLoadMeshHierarchyFromXInMemory(buffer
, size
, options
, device
,
3725 alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3727 UnmapViewOfFile(buffer
);
3732 static HRESULT
filedata_get_name(ID3DXFileData
*filedata
, char **name
)
3737 hr
= filedata
->lpVtbl
->GetName(filedata
, NULL
, &name_len
);
3738 if (FAILED(hr
)) return hr
;
3742 *name
= HeapAlloc(GetProcessHeap(), 0, name_len
);
3743 if (!*name
) return E_OUTOFMEMORY
;
3745 hr
= filedata
->lpVtbl
->GetName(filedata
, *name
, &name_len
);
3747 HeapFree(GetProcessHeap(), 0, *name
);
3754 static HRESULT
load_mesh_container(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3755 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXMESHCONTAINER
**mesh_container
)
3758 ID3DXBuffer
*adjacency
= NULL
;
3759 ID3DXBuffer
*materials
= NULL
;
3760 ID3DXBuffer
*effects
= NULL
;
3761 ID3DXSkinInfo
*skin_info
= NULL
;
3762 D3DXMESHDATA mesh_data
;
3763 DWORD num_materials
= 0;
3766 mesh_data
.Type
= D3DXMESHTYPE_MESH
;
3767 mesh_data
.u
.pMesh
= NULL
;
3769 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
3770 &adjacency
, &materials
, &effects
, &num_materials
,
3771 &skin_info
, &mesh_data
.u
.pMesh
);
3772 if (FAILED(hr
)) return hr
;
3774 hr
= filedata_get_name(filedata
, &name
);
3775 if (FAILED(hr
)) goto cleanup
;
3777 hr
= alloc_hier
->lpVtbl
->CreateMeshContainer(alloc_hier
, name
, &mesh_data
,
3778 materials
? ID3DXBuffer_GetBufferPointer(materials
) : NULL
,
3779 effects
? ID3DXBuffer_GetBufferPointer(effects
) : NULL
,
3781 adjacency
? ID3DXBuffer_GetBufferPointer(adjacency
) : NULL
,
3782 skin_info
, mesh_container
);
3785 if (materials
) ID3DXBuffer_Release(materials
);
3786 if (effects
) ID3DXBuffer_Release(effects
);
3787 if (adjacency
) ID3DXBuffer_Release(adjacency
);
3788 if (skin_info
) IUnknown_Release(skin_info
);
3789 if (mesh_data
.u
.pMesh
) IUnknown_Release(mesh_data
.u
.pMesh
);
3790 HeapFree(GetProcessHeap(), 0, name
);
3794 static HRESULT
parse_transform_matrix(ID3DXFileData
*filedata
, D3DXMATRIX
*transform
)
3800 /* template Matrix4x4 {
3801 * array FLOAT matrix[16];
3803 * template FrameTransformMatrix {
3804 * Matrix4x4 frameMatrix;
3808 hr
= filedata
->lpVtbl
->Lock(filedata
, &data_size
, (const void**)&data
);
3809 if (FAILED(hr
)) return hr
;
3811 if (data_size
!= sizeof(D3DXMATRIX
)) {
3812 WARN("incorrect data size (%ld bytes)\n", data_size
);
3813 filedata
->lpVtbl
->Unlock(filedata
);
3817 memcpy(transform
, data
, sizeof(D3DXMATRIX
));
3819 filedata
->lpVtbl
->Unlock(filedata
);
3823 static HRESULT
load_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
3824 struct ID3DXAllocateHierarchy
*alloc_hier
, D3DXFRAME
**frame_out
)
3828 ID3DXFileData
*child
;
3830 D3DXFRAME
*frame
= NULL
;
3831 D3DXMESHCONTAINER
**next_container
;
3832 D3DXFRAME
**next_child
;
3836 hr
= filedata_get_name(filedata
, &name
);
3837 if (FAILED(hr
)) return hr
;
3839 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, name
, frame_out
);
3840 HeapFree(GetProcessHeap(), 0, name
);
3841 if (FAILED(hr
)) return E_FAIL
;
3844 D3DXMatrixIdentity(&frame
->TransformationMatrix
);
3845 next_child
= &frame
->pFrameFirstChild
;
3846 next_container
= &frame
->pMeshContainer
;
3848 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
3852 for (i
= 0; i
< nb_children
; i
++)
3854 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
3857 hr
= child
->lpVtbl
->GetType(child
, &type
);
3861 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
3862 hr
= load_mesh_container(child
, options
, device
, alloc_hier
, next_container
);
3864 next_container
= &(*next_container
)->pNextMeshContainer
;
3865 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
3866 hr
= parse_transform_matrix(child
, &frame
->TransformationMatrix
);
3867 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
3868 hr
= load_frame(child
, options
, device
, alloc_hier
, next_child
);
3870 next_child
= &(*next_child
)->pFrameSibling
;
3879 HRESULT WINAPI
D3DXLoadMeshHierarchyFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
3880 struct IDirect3DDevice9
*device
, struct ID3DXAllocateHierarchy
*alloc_hier
,
3881 struct ID3DXLoadUserData
*load_user_data
, D3DXFRAME
**frame_hierarchy
,
3882 struct ID3DXAnimationController
**anim_controller
)
3885 ID3DXFile
*d3dxfile
= NULL
;
3886 ID3DXFileEnumObject
*enumobj
= NULL
;
3887 ID3DXFileData
*filedata
= NULL
;
3888 D3DXF_FILELOADMEMORY source
;
3889 D3DXFRAME
*first_frame
= NULL
;
3890 D3DXFRAME
**next_frame
= &first_frame
;
3895 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
3896 device
, alloc_hier
, load_user_data
, frame_hierarchy
, anim_controller
);
3898 if (!memory
|| !memory_size
|| !device
|| !frame_hierarchy
|| !alloc_hier
)
3899 return D3DERR_INVALIDCALL
;
3900 if (load_user_data
|| anim_controller
) {
3902 FIXME("Loading user data not implemented\n");
3903 if (anim_controller
)
3904 FIXME("Animation controller creation not implemented\n");
3908 hr
= D3DXFileCreate(&d3dxfile
);
3909 if (FAILED(hr
)) goto cleanup
;
3911 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
3912 if (FAILED(hr
)) goto cleanup
;
3914 source
.lpMemory
= (void*)memory
;
3915 source
.dSize
= memory_size
;
3916 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
3917 if (FAILED(hr
)) goto cleanup
;
3919 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
3923 for (i
= 0; i
< nb_children
; i
++)
3925 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
3929 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
3930 if (SUCCEEDED(hr
)) {
3931 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
3932 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, next_frame
);
3938 D3DXMatrixIdentity(&(*next_frame
)->TransformationMatrix
);
3940 hr
= load_mesh_container(filedata
, options
, device
, alloc_hier
, &(*next_frame
)->pMeshContainer
);
3941 if (FAILED(hr
)) goto cleanup
;
3942 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
3943 hr
= load_frame(filedata
, options
, device
, alloc_hier
, next_frame
);
3944 if (FAILED(hr
)) goto cleanup
;
3947 next_frame
= &(*next_frame
)->pFrameSibling
;
3950 filedata
->lpVtbl
->Release(filedata
);
3958 } else if (first_frame
->pFrameSibling
) {
3959 D3DXFRAME
*root_frame
= NULL
;
3960 hr
= alloc_hier
->lpVtbl
->CreateFrame(alloc_hier
, NULL
, &root_frame
);
3965 D3DXMatrixIdentity(&root_frame
->TransformationMatrix
);
3966 root_frame
->pFrameFirstChild
= first_frame
;
3967 *frame_hierarchy
= root_frame
;
3970 *frame_hierarchy
= first_frame
;
3975 if (FAILED(hr
) && first_frame
) D3DXFrameDestroy(first_frame
, alloc_hier
);
3976 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
3977 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
3978 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
3982 HRESULT WINAPI
D3DXCleanMesh(D3DXCLEANTYPE clean_type
, ID3DXMesh
*mesh_in
, const DWORD
*adjacency_in
,
3983 ID3DXMesh
**mesh_out
, DWORD
*adjacency_out
, ID3DXBuffer
**errors_and_warnings
)
3985 FIXME("(%u, %p, %p, %p, %p, %p)\n", clean_type
, mesh_in
, adjacency_in
, mesh_out
, adjacency_out
, errors_and_warnings
);
3990 HRESULT WINAPI
D3DXFrameDestroy(D3DXFRAME
*frame
, ID3DXAllocateHierarchy
*alloc_hier
)
3995 TRACE("(%p, %p)\n", frame
, alloc_hier
);
3997 if (!frame
|| !alloc_hier
)
3998 return D3DERR_INVALIDCALL
;
4001 D3DXMESHCONTAINER
*container
;
4002 D3DXFRAME
*current_frame
;
4004 if (frame
->pFrameSibling
) {
4005 current_frame
= frame
->pFrameSibling
;
4006 frame
->pFrameSibling
= current_frame
->pFrameSibling
;
4007 current_frame
->pFrameSibling
= NULL
;
4009 current_frame
= frame
;
4013 if (current_frame
->pFrameFirstChild
) {
4014 hr
= D3DXFrameDestroy(current_frame
->pFrameFirstChild
, alloc_hier
);
4015 if (FAILED(hr
)) return hr
;
4016 current_frame
->pFrameFirstChild
= NULL
;
4019 container
= current_frame
->pMeshContainer
;
4021 D3DXMESHCONTAINER
*next_container
= container
->pNextMeshContainer
;
4022 hr
= alloc_hier
->lpVtbl
->DestroyMeshContainer(alloc_hier
, container
);
4023 if (FAILED(hr
)) return hr
;
4024 container
= next_container
;
4026 hr
= alloc_hier
->lpVtbl
->DestroyFrame(alloc_hier
, current_frame
);
4027 if (FAILED(hr
)) return hr
;
4032 HRESULT WINAPI
D3DXLoadMeshFromXA(const char *filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4033 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4034 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4040 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_a(filename
), options
,
4041 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4044 return D3DERR_INVALIDCALL
;
4046 len
= MultiByteToWideChar(CP_ACP
, 0, filename
, -1, NULL
, 0);
4047 filenameW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4048 if (!filenameW
) return E_OUTOFMEMORY
;
4049 MultiByteToWideChar(CP_ACP
, 0, filename
, -1, filenameW
, len
);
4051 hr
= D3DXLoadMeshFromXW(filenameW
, options
, device
, adjacency
, materials
,
4052 effect_instances
, num_materials
, mesh
);
4053 HeapFree(GetProcessHeap(), 0, filenameW
);
4058 HRESULT WINAPI
D3DXLoadMeshFromXW(const WCHAR
*filename
, DWORD options
, struct IDirect3DDevice9
*device
,
4059 struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
, struct ID3DXBuffer
**effect_instances
,
4060 DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4066 TRACE("(%s, %x, %p, %p, %p, %p, %p, %p)\n", debugstr_w(filename
), options
,
4067 device
, adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4070 return D3DERR_INVALIDCALL
;
4072 hr
= map_view_of_file(filename
, &buffer
, &size
);
4074 return D3DXERR_INVALIDDATA
;
4076 hr
= D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4077 materials
, effect_instances
, num_materials
, mesh
);
4079 UnmapViewOfFile(buffer
);
4084 HRESULT WINAPI
D3DXLoadMeshFromXResource(HMODULE module
, const char *name
, const char *type
, DWORD options
,
4085 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency
, struct ID3DXBuffer
**materials
,
4086 struct ID3DXBuffer
**effect_instances
, DWORD
*num_materials
, struct ID3DXMesh
**mesh
)
4093 TRACE("(%p, %s, %s, %x, %p, %p, %p, %p, %p, %p)\n",
4094 module
, debugstr_a(name
), debugstr_a(type
), options
, device
,
4095 adjacency
, materials
, effect_instances
, num_materials
, mesh
);
4097 resinfo
= FindResourceA(module
, name
, type
);
4098 if (!resinfo
) return D3DXERR_INVALIDDATA
;
4100 hr
= load_resource_into_memory(module
, resinfo
, &buffer
, &size
);
4101 if (FAILED(hr
)) return D3DXERR_INVALIDDATA
;
4103 return D3DXLoadMeshFromXInMemory(buffer
, size
, options
, device
, adjacency
,
4104 materials
, effect_instances
, num_materials
, mesh
);
4107 struct mesh_container
4111 ID3DXBuffer
*adjacency
;
4112 ID3DXBuffer
*materials
;
4113 ID3DXBuffer
*effects
;
4114 DWORD num_materials
;
4115 D3DXMATRIX transform
;
4118 static HRESULT
parse_frame(struct ID3DXFileData
*filedata
, DWORD options
, struct IDirect3DDevice9
*device
,
4119 const D3DXMATRIX
*parent_transform
, struct list
*container_list
, DWORD provide_flags
)
4122 D3DXMATRIX transform
= *parent_transform
;
4123 ID3DXFileData
*child
;
4128 hr
= filedata
->lpVtbl
->GetChildren(filedata
, &nb_children
);
4132 for (i
= 0; i
< nb_children
; i
++)
4134 hr
= filedata
->lpVtbl
->GetChild(filedata
, i
, &child
);
4137 hr
= child
->lpVtbl
->GetType(child
, &type
);
4141 if (IsEqualGUID(&type
, &TID_D3DRMMesh
)) {
4142 struct mesh_container
*container
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container
));
4144 return E_OUTOFMEMORY
;
4145 list_add_tail(container_list
, &container
->entry
);
4146 container
->transform
= transform
;
4148 hr
= D3DXLoadSkinMeshFromXof(child
, options
, device
,
4149 (provide_flags
& PROVIDE_ADJACENCY
) ? &container
->adjacency
: NULL
,
4150 (provide_flags
& PROVIDE_MATERIALS
) ? &container
->materials
: NULL
,
4151 NULL
, &container
->num_materials
, NULL
, &container
->mesh
);
4152 } else if (IsEqualGUID(&type
, &TID_D3DRMFrameTransformMatrix
)) {
4153 D3DXMATRIX new_transform
;
4154 hr
= parse_transform_matrix(child
, &new_transform
);
4155 D3DXMatrixMultiply(&transform
, &transform
, &new_transform
);
4156 } else if (IsEqualGUID(&type
, &TID_D3DRMFrame
)) {
4157 hr
= parse_frame(child
, options
, device
, &transform
, container_list
, provide_flags
);
4166 HRESULT WINAPI
D3DXLoadMeshFromXInMemory(const void *memory
, DWORD memory_size
, DWORD options
,
4167 struct IDirect3DDevice9
*device
, struct ID3DXBuffer
**adjacency_out
, struct ID3DXBuffer
**materials_out
,
4168 struct ID3DXBuffer
**effects_out
, DWORD
*num_materials_out
, struct ID3DXMesh
**mesh_out
)
4171 ID3DXFile
*d3dxfile
= NULL
;
4172 ID3DXFileEnumObject
*enumobj
= NULL
;
4173 ID3DXFileData
*filedata
= NULL
;
4174 D3DXF_FILELOADMEMORY source
;
4175 ID3DXBuffer
*materials
= NULL
;
4176 ID3DXBuffer
*effects
= NULL
;
4177 ID3DXBuffer
*adjacency
= NULL
;
4178 struct list container_list
= LIST_INIT(container_list
);
4179 struct mesh_container
*container_ptr
, *next_container_ptr
;
4180 DWORD num_materials
;
4181 DWORD num_faces
, num_vertices
;
4182 D3DXMATRIX identity
;
4183 DWORD provide_flags
= 0;
4185 ID3DXMesh
*concat_mesh
= NULL
;
4186 D3DVERTEXELEMENT9 concat_decl
[MAX_FVF_DECL_SIZE
];
4187 BYTE
*concat_vertices
= NULL
;
4188 void *concat_indices
= NULL
;
4190 DWORD concat_vertex_size
;
4195 TRACE("(%p, %u, %x, %p, %p, %p, %p, %p, %p)\n", memory
, memory_size
, options
,
4196 device
, adjacency_out
, materials_out
, effects_out
, num_materials_out
, mesh_out
);
4198 if (!memory
|| !memory_size
|| !device
|| !mesh_out
)
4199 return D3DERR_INVALIDCALL
;
4201 hr
= D3DXFileCreate(&d3dxfile
);
4202 if (FAILED(hr
)) goto cleanup
;
4204 hr
= d3dxfile
->lpVtbl
->RegisterTemplates(d3dxfile
, D3DRM_XTEMPLATES
, D3DRM_XTEMPLATE_BYTES
);
4205 if (FAILED(hr
)) goto cleanup
;
4207 source
.lpMemory
= (void*)memory
;
4208 source
.dSize
= memory_size
;
4209 hr
= d3dxfile
->lpVtbl
->CreateEnumObject(d3dxfile
, &source
, D3DXF_FILELOAD_FROMMEMORY
, &enumobj
);
4210 if (FAILED(hr
)) goto cleanup
;
4212 D3DXMatrixIdentity(&identity
);
4213 if (adjacency_out
) provide_flags
|= PROVIDE_ADJACENCY
;
4214 if (materials_out
|| effects_out
) provide_flags
|= PROVIDE_MATERIALS
;
4216 hr
= enumobj
->lpVtbl
->GetChildren(enumobj
, &nb_children
);
4220 for (i
= 0; i
< nb_children
; i
++)
4222 hr
= enumobj
->lpVtbl
->GetChild(enumobj
, i
, &filedata
);
4226 hr
= filedata
->lpVtbl
->GetType(filedata
, &guid
);
4227 if (SUCCEEDED(hr
)) {
4228 if (IsEqualGUID(&guid
, &TID_D3DRMMesh
)) {
4229 container_ptr
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*container_ptr
));
4230 if (!container_ptr
) {
4234 list_add_tail(&container_list
, &container_ptr
->entry
);
4235 D3DXMatrixIdentity(&container_ptr
->transform
);
4237 hr
= D3DXLoadSkinMeshFromXof(filedata
, options
, device
,
4238 (provide_flags
& PROVIDE_ADJACENCY
) ? &container_ptr
->adjacency
: NULL
,
4239 (provide_flags
& PROVIDE_MATERIALS
) ? &container_ptr
->materials
: NULL
,
4240 NULL
, &container_ptr
->num_materials
, NULL
, &container_ptr
->mesh
);
4241 } else if (IsEqualGUID(&guid
, &TID_D3DRMFrame
)) {
4242 hr
= parse_frame(filedata
, options
, device
, &identity
, &container_list
, provide_flags
);
4244 if (FAILED(hr
)) goto cleanup
;
4246 filedata
->lpVtbl
->Release(filedata
);
4252 enumobj
->lpVtbl
->Release(enumobj
);
4254 d3dxfile
->lpVtbl
->Release(d3dxfile
);
4257 if (list_empty(&container_list
)) {
4266 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4268 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4269 fvf
|= mesh
->lpVtbl
->GetFVF(mesh
);
4270 num_faces
+= mesh
->lpVtbl
->GetNumFaces(mesh
);
4271 num_vertices
+= mesh
->lpVtbl
->GetNumVertices(mesh
);
4272 num_materials
+= container_ptr
->num_materials
;
4275 hr
= D3DXCreateMeshFVF(num_faces
, num_vertices
, options
, fvf
, device
, &concat_mesh
);
4276 if (FAILED(hr
)) goto cleanup
;
4278 hr
= concat_mesh
->lpVtbl
->GetDeclaration(concat_mesh
, concat_decl
);
4279 if (FAILED(hr
)) goto cleanup
;
4281 concat_vertex_size
= D3DXGetDeclVertexSize(concat_decl
, 0);
4283 hr
= concat_mesh
->lpVtbl
->LockVertexBuffer(concat_mesh
, 0, (void**)&concat_vertices
);
4284 if (FAILED(hr
)) goto cleanup
;
4286 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4288 D3DVERTEXELEMENT9 mesh_decl
[MAX_FVF_DECL_SIZE
];
4289 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4290 DWORD num_mesh_vertices
= mesh
->lpVtbl
->GetNumVertices(mesh
);
4291 DWORD mesh_vertex_size
;
4292 const BYTE
*mesh_vertices
;
4295 hr
= mesh
->lpVtbl
->GetDeclaration(mesh
, mesh_decl
);
4296 if (FAILED(hr
)) goto cleanup
;
4298 mesh_vertex_size
= D3DXGetDeclVertexSize(mesh_decl
, 0);
4300 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_vertices
);
4301 if (FAILED(hr
)) goto cleanup
;
4303 for (i
= 0; i
< num_mesh_vertices
; i
++) {
4307 D3DXVec3TransformCoord((D3DXVECTOR3
*)concat_vertices
,
4308 (D3DXVECTOR3
*)mesh_vertices
,
4309 &container_ptr
->transform
);
4310 for (j
= 1; concat_decl
[j
].Stream
!= 0xff; j
++)
4312 if (concat_decl
[j
].Usage
== mesh_decl
[k
].Usage
&&
4313 concat_decl
[j
].UsageIndex
== mesh_decl
[k
].UsageIndex
)
4315 if (concat_decl
[j
].Usage
== D3DDECLUSAGE_NORMAL
) {
4316 D3DXVec3TransformCoord((D3DXVECTOR3
*)(concat_vertices
+ concat_decl
[j
].Offset
),
4317 (D3DXVECTOR3
*)(mesh_vertices
+ mesh_decl
[k
].Offset
),
4318 &container_ptr
->transform
);
4320 memcpy(concat_vertices
+ concat_decl
[j
].Offset
,
4321 mesh_vertices
+ mesh_decl
[k
].Offset
,
4322 d3dx_decltype_size
[mesh_decl
[k
].Type
]);
4327 mesh_vertices
+= mesh_vertex_size
;
4328 concat_vertices
+= concat_vertex_size
;
4331 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
4334 concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4335 concat_vertices
= NULL
;
4337 hr
= concat_mesh
->lpVtbl
->LockIndexBuffer(concat_mesh
, 0, &concat_indices
);
4338 if (FAILED(hr
)) goto cleanup
;
4341 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4343 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4344 const void *mesh_indices
;
4345 DWORD num_mesh_faces
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4348 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, D3DLOCK_READONLY
, (void**)&mesh_indices
);
4349 if (FAILED(hr
)) goto cleanup
;
4351 if (options
& D3DXMESH_32BIT
) {
4352 DWORD
*dest
= concat_indices
;
4353 const DWORD
*src
= mesh_indices
;
4354 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4355 *dest
++ = index_offset
+ *src
++;
4356 concat_indices
= dest
;
4358 WORD
*dest
= concat_indices
;
4359 const WORD
*src
= mesh_indices
;
4360 for (i
= 0; i
< num_mesh_faces
* 3; i
++)
4361 *dest
++ = index_offset
+ *src
++;
4362 concat_indices
= dest
;
4364 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
4366 index_offset
+= num_mesh_faces
* 3;
4369 concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4370 concat_indices
= NULL
;
4372 if (num_materials
) {
4373 DWORD
*concat_attrib_buffer
= NULL
;
4376 hr
= concat_mesh
->lpVtbl
->LockAttributeBuffer(concat_mesh
, 0, &concat_attrib_buffer
);
4377 if (FAILED(hr
)) goto cleanup
;
4379 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4381 ID3DXMesh
*mesh
= container_ptr
->mesh
;
4382 const DWORD
*mesh_attrib_buffer
= NULL
;
4383 DWORD count
= mesh
->lpVtbl
->GetNumFaces(mesh
);
4385 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, D3DLOCK_READONLY
, (DWORD
**)&mesh_attrib_buffer
);
4387 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4392 *concat_attrib_buffer
++ = offset
+ *mesh_attrib_buffer
++;
4394 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
4395 offset
+= container_ptr
->num_materials
;
4397 concat_mesh
->lpVtbl
->UnlockAttributeBuffer(concat_mesh
);
4400 if (materials_out
|| effects_out
) {
4401 D3DXMATERIAL
*out_ptr
;
4402 if (!num_materials
) {
4403 /* create default material */
4404 hr
= D3DXCreateBuffer(sizeof(D3DXMATERIAL
), &materials
);
4405 if (FAILED(hr
)) goto cleanup
;
4407 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4408 out_ptr
->MatD3D
.Diffuse
.r
= 0.5f
;
4409 out_ptr
->MatD3D
.Diffuse
.g
= 0.5f
;
4410 out_ptr
->MatD3D
.Diffuse
.b
= 0.5f
;
4411 out_ptr
->MatD3D
.Specular
.r
= 0.5f
;
4412 out_ptr
->MatD3D
.Specular
.g
= 0.5f
;
4413 out_ptr
->MatD3D
.Specular
.b
= 0.5f
;
4414 /* D3DXCreateBuffer initializes the rest to zero */
4416 DWORD buffer_size
= num_materials
* sizeof(D3DXMATERIAL
);
4417 char *strings_out_ptr
;
4419 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4421 if (container_ptr
->materials
) {
4423 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4424 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4426 if (in_ptr
->pTextureFilename
)
4427 buffer_size
+= strlen(in_ptr
->pTextureFilename
) + 1;
4433 hr
= D3DXCreateBuffer(buffer_size
, &materials
);
4434 if (FAILED(hr
)) goto cleanup
;
4435 out_ptr
= ID3DXBuffer_GetBufferPointer(materials
);
4436 strings_out_ptr
= (char*)(out_ptr
+ num_materials
);
4438 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4440 if (container_ptr
->materials
) {
4442 const D3DXMATERIAL
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->materials
);
4443 for (i
= 0; i
< container_ptr
->num_materials
; i
++)
4445 out_ptr
->MatD3D
= in_ptr
->MatD3D
;
4446 if (in_ptr
->pTextureFilename
) {
4447 out_ptr
->pTextureFilename
= strings_out_ptr
;
4448 strcpy(out_ptr
->pTextureFilename
, in_ptr
->pTextureFilename
);
4449 strings_out_ptr
+= strlen(in_ptr
->pTextureFilename
) + 1;
4462 generate_effects(materials
, num_materials
, &effects
);
4463 if (!materials_out
) {
4464 ID3DXBuffer_Release(materials
);
4469 if (adjacency_out
) {
4470 if (!list_next(&container_list
, list_head(&container_list
))) {
4471 container_ptr
= LIST_ENTRY(list_head(&container_list
), struct mesh_container
, entry
);
4472 adjacency
= container_ptr
->adjacency
;
4473 container_ptr
->adjacency
= NULL
;
4478 hr
= D3DXCreateBuffer(num_faces
* 3 * sizeof(DWORD
), &adjacency
);
4479 if (FAILED(hr
)) goto cleanup
;
4481 out_ptr
= ID3DXBuffer_GetBufferPointer(adjacency
);
4482 LIST_FOR_EACH_ENTRY(container_ptr
, &container_list
, struct mesh_container
, entry
)
4485 DWORD count
= 3 * container_ptr
->mesh
->lpVtbl
->GetNumFaces(container_ptr
->mesh
);
4486 DWORD
*in_ptr
= ID3DXBuffer_GetBufferPointer(container_ptr
->adjacency
);
4488 for (i
= 0; i
< count
; i
++)
4489 *out_ptr
++ = offset
+ *in_ptr
++;
4496 *mesh_out
= concat_mesh
;
4497 if (adjacency_out
) *adjacency_out
= adjacency
;
4498 if (materials_out
) *materials_out
= materials
;
4499 if (effects_out
) *effects_out
= effects
;
4500 if (num_materials_out
) *num_materials_out
= num_materials
;
4504 if (concat_indices
) concat_mesh
->lpVtbl
->UnlockIndexBuffer(concat_mesh
);
4505 if (concat_vertices
) concat_mesh
->lpVtbl
->UnlockVertexBuffer(concat_mesh
);
4506 if (filedata
) filedata
->lpVtbl
->Release(filedata
);
4507 if (enumobj
) enumobj
->lpVtbl
->Release(enumobj
);
4508 if (d3dxfile
) d3dxfile
->lpVtbl
->Release(d3dxfile
);
4510 if (concat_mesh
) IUnknown_Release(concat_mesh
);
4511 if (materials
) ID3DXBuffer_Release(materials
);
4512 if (effects
) ID3DXBuffer_Release(effects
);
4513 if (adjacency
) ID3DXBuffer_Release(adjacency
);
4515 LIST_FOR_EACH_ENTRY_SAFE(container_ptr
, next_container_ptr
, &container_list
, struct mesh_container
, entry
)
4517 if (container_ptr
->mesh
) IUnknown_Release(container_ptr
->mesh
);
4518 if (container_ptr
->adjacency
) ID3DXBuffer_Release(container_ptr
->adjacency
);
4519 if (container_ptr
->materials
) ID3DXBuffer_Release(container_ptr
->materials
);
4520 if (container_ptr
->effects
) ID3DXBuffer_Release(container_ptr
->effects
);
4521 HeapFree(GetProcessHeap(), 0, container_ptr
);
4526 HRESULT WINAPI
D3DXCreateBox(struct IDirect3DDevice9
*device
, float width
, float height
,
4527 float depth
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4529 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device
, width
, height
, depth
, mesh
, adjacency
);
4536 D3DXVECTOR3 position
;
4540 typedef WORD face
[3];
4548 static void free_sincos_table(struct sincos_table
*sincos_table
)
4550 HeapFree(GetProcessHeap(), 0, sincos_table
->cos
);
4551 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4554 /* pre compute sine and cosine tables; caller must free */
4555 static BOOL
compute_sincos_table(struct sincos_table
*sincos_table
, float angle_start
, float angle_step
, int n
)
4560 sincos_table
->sin
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->sin
));
4561 if (!sincos_table
->sin
)
4565 sincos_table
->cos
= HeapAlloc(GetProcessHeap(), 0, n
* sizeof(*sincos_table
->cos
));
4566 if (!sincos_table
->cos
)
4568 HeapFree(GetProcessHeap(), 0, sincos_table
->sin
);
4572 angle
= angle_start
;
4573 for (i
= 0; i
< n
; i
++)
4575 sincos_table
->sin
[i
] = sin(angle
);
4576 sincos_table
->cos
[i
] = cos(angle
);
4577 angle
+= angle_step
;
4583 static WORD
vertex_index(UINT slices
, int slice
, int stack
)
4585 return stack
*slices
+slice
+1;
4588 HRESULT WINAPI
D3DXCreateSphere(struct IDirect3DDevice9
*device
, float radius
, UINT slices
,
4589 UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4591 DWORD number_of_vertices
, number_of_faces
;
4594 struct vertex
*vertices
;
4596 float phi_step
, phi_start
;
4597 struct sincos_table phi
;
4598 float theta_step
, theta
, sin_theta
, cos_theta
;
4599 DWORD vertex
, face
, stack
, slice
;
4601 TRACE("(%p, %f, %u, %u, %p, %p)\n", device
, radius
, slices
, stacks
, mesh
, adjacency
);
4603 if (!device
|| radius
< 0.0f
|| slices
< 2 || stacks
< 2 || !mesh
)
4605 return D3DERR_INVALIDCALL
;
4610 FIXME("Case of adjacency != NULL not implemented.\n");
4614 number_of_vertices
= 2 + slices
* (stacks
-1);
4615 number_of_faces
= 2 * slices
+ (stacks
- 2) * (2 * slices
);
4617 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4618 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &sphere
);
4624 hr
= sphere
->lpVtbl
->LockVertexBuffer(sphere
, 0, (LPVOID
*)&vertices
);
4627 sphere
->lpVtbl
->Release(sphere
);
4631 hr
= sphere
->lpVtbl
->LockIndexBuffer(sphere
, 0, (LPVOID
*)&faces
);
4634 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4635 sphere
->lpVtbl
->Release(sphere
);
4639 /* phi = angle on xz plane wrt z axis */
4640 phi_step
= -2 * M_PI
/ slices
;
4641 phi_start
= M_PI
/ 2;
4643 if (!compute_sincos_table(&phi
, phi_start
, phi_step
, slices
))
4645 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4646 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4647 sphere
->lpVtbl
->Release(sphere
);
4648 return E_OUTOFMEMORY
;
4651 /* theta = angle on xy plane wrt x axis */
4652 theta_step
= M_PI
/ stacks
;
4658 vertices
[vertex
].normal
.x
= 0.0f
;
4659 vertices
[vertex
].normal
.y
= 0.0f
;
4660 vertices
[vertex
].normal
.z
= 1.0f
;
4661 vertices
[vertex
].position
.x
= 0.0f
;
4662 vertices
[vertex
].position
.y
= 0.0f
;
4663 vertices
[vertex
].position
.z
= radius
;
4666 for (stack
= 0; stack
< stacks
- 1; stack
++)
4668 sin_theta
= sin(theta
);
4669 cos_theta
= cos(theta
);
4671 for (slice
= 0; slice
< slices
; slice
++)
4673 vertices
[vertex
].normal
.x
= sin_theta
* phi
.cos
[slice
];
4674 vertices
[vertex
].normal
.y
= sin_theta
* phi
.sin
[slice
];
4675 vertices
[vertex
].normal
.z
= cos_theta
;
4676 vertices
[vertex
].position
.x
= radius
* sin_theta
* phi
.cos
[slice
];
4677 vertices
[vertex
].position
.y
= radius
* sin_theta
* phi
.sin
[slice
];
4678 vertices
[vertex
].position
.z
= radius
* cos_theta
;
4685 /* top stack is triangle fan */
4687 faces
[face
][1] = slice
+ 1;
4688 faces
[face
][2] = slice
;
4693 /* stacks in between top and bottom are quad strips */
4694 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4695 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4696 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4699 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4700 faces
[face
][1] = vertex_index(slices
, slice
, stack
);
4701 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4707 theta
+= theta_step
;
4713 faces
[face
][2] = slice
;
4718 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4719 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4720 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4723 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4724 faces
[face
][1] = vertex_index(slices
, 0, stack
);
4725 faces
[face
][2] = vertex_index(slices
, slice
-1, stack
);
4730 vertices
[vertex
].position
.x
= 0.0f
;
4731 vertices
[vertex
].position
.y
= 0.0f
;
4732 vertices
[vertex
].position
.z
= -radius
;
4733 vertices
[vertex
].normal
.x
= 0.0f
;
4734 vertices
[vertex
].normal
.y
= 0.0f
;
4735 vertices
[vertex
].normal
.z
= -1.0f
;
4737 /* bottom stack is triangle fan */
4738 for (slice
= 1; slice
< slices
; slice
++)
4740 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4741 faces
[face
][1] = vertex_index(slices
, slice
, stack
-1);
4742 faces
[face
][2] = vertex
;
4746 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4747 faces
[face
][1] = vertex_index(slices
, 0, stack
-1);
4748 faces
[face
][2] = vertex
;
4750 free_sincos_table(&phi
);
4751 sphere
->lpVtbl
->UnlockIndexBuffer(sphere
);
4752 sphere
->lpVtbl
->UnlockVertexBuffer(sphere
);
4758 HRESULT WINAPI
D3DXCreateCylinder(struct IDirect3DDevice9
*device
, float radius1
, float radius2
,
4759 float length
, UINT slices
, UINT stacks
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4761 DWORD number_of_vertices
, number_of_faces
;
4763 ID3DXMesh
*cylinder
;
4764 struct vertex
*vertices
;
4766 float theta_step
, theta_start
;
4767 struct sincos_table theta
;
4768 float delta_radius
, radius
, radius_step
;
4769 float z
, z_step
, z_normal
;
4770 DWORD vertex
, face
, slice
, stack
;
4772 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device
, radius1
, radius2
, length
, slices
, stacks
, mesh
, adjacency
);
4774 if (device
== NULL
|| radius1
< 0.0f
|| radius2
< 0.0f
|| length
< 0.0f
|| slices
< 2 || stacks
< 1 || mesh
== NULL
)
4776 return D3DERR_INVALIDCALL
;
4781 FIXME("Case of adjacency != NULL not implemented.\n");
4785 number_of_vertices
= 2 + (slices
* (3 + stacks
));
4786 number_of_faces
= 2 * slices
+ stacks
* (2 * slices
);
4788 hr
= D3DXCreateMeshFVF(number_of_faces
, number_of_vertices
, D3DXMESH_MANAGED
,
4789 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &cylinder
);
4795 hr
= cylinder
->lpVtbl
->LockVertexBuffer(cylinder
, 0, (LPVOID
*)&vertices
);
4798 cylinder
->lpVtbl
->Release(cylinder
);
4802 hr
= cylinder
->lpVtbl
->LockIndexBuffer(cylinder
, 0, (LPVOID
*)&faces
);
4805 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4806 cylinder
->lpVtbl
->Release(cylinder
);
4810 /* theta = angle on xy plane wrt x axis */
4811 theta_step
= -2 * M_PI
/ slices
;
4812 theta_start
= M_PI
/ 2;
4814 if (!compute_sincos_table(&theta
, theta_start
, theta_step
, slices
))
4816 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4817 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4818 cylinder
->lpVtbl
->Release(cylinder
);
4819 return E_OUTOFMEMORY
;
4825 delta_radius
= radius1
- radius2
;
4827 radius_step
= delta_radius
/ stacks
;
4830 z_step
= length
/ stacks
;
4831 z_normal
= delta_radius
/ length
;
4832 if (isnan(z_normal
))
4837 vertices
[vertex
].normal
.x
= 0.0f
;
4838 vertices
[vertex
].normal
.y
= 0.0f
;
4839 vertices
[vertex
].normal
.z
= -1.0f
;
4840 vertices
[vertex
].position
.x
= 0.0f
;
4841 vertices
[vertex
].position
.y
= 0.0f
;
4842 vertices
[vertex
++].position
.z
= z
;
4844 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4846 vertices
[vertex
].normal
.x
= 0.0f
;
4847 vertices
[vertex
].normal
.y
= 0.0f
;
4848 vertices
[vertex
].normal
.z
= -1.0f
;
4849 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4850 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4851 vertices
[vertex
].position
.z
= z
;
4856 faces
[face
][1] = slice
;
4857 faces
[face
++][2] = slice
+ 1;
4862 faces
[face
][1] = slice
;
4863 faces
[face
++][2] = 1;
4865 for (stack
= 1; stack
<= stacks
+1; stack
++)
4867 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4869 vertices
[vertex
].normal
.x
= theta
.cos
[slice
];
4870 vertices
[vertex
].normal
.y
= theta
.sin
[slice
];
4871 vertices
[vertex
].normal
.z
= z_normal
;
4872 D3DXVec3Normalize(&vertices
[vertex
].normal
, &vertices
[vertex
].normal
);
4873 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4874 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4875 vertices
[vertex
].position
.z
= z
;
4877 if (stack
> 1 && slice
> 0)
4879 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4880 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4881 faces
[face
++][2] = vertex_index(slices
, slice
, stack
-1);
4883 faces
[face
][0] = vertex_index(slices
, slice
, stack
-1);
4884 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4885 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4891 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
-1);
4892 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4893 faces
[face
++][2] = vertex_index(slices
, 0, stack
-1);
4895 faces
[face
][0] = vertex_index(slices
, 0, stack
-1);
4896 faces
[face
][1] = vertex_index(slices
, slice
-1, stack
);
4897 faces
[face
++][2] = vertex_index(slices
, 0, stack
);
4900 if (stack
< stacks
+ 1)
4903 radius
-= radius_step
;
4907 for (slice
= 0; slice
< slices
; slice
++, vertex
++)
4909 vertices
[vertex
].normal
.x
= 0.0f
;
4910 vertices
[vertex
].normal
.y
= 0.0f
;
4911 vertices
[vertex
].normal
.z
= 1.0f
;
4912 vertices
[vertex
].position
.x
= radius
* theta
.cos
[slice
];
4913 vertices
[vertex
].position
.y
= radius
* theta
.sin
[slice
];
4914 vertices
[vertex
].position
.z
= z
;
4918 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4919 faces
[face
][1] = number_of_vertices
- 1;
4920 faces
[face
++][2] = vertex_index(slices
, slice
, stack
);
4924 vertices
[vertex
].position
.x
= 0.0f
;
4925 vertices
[vertex
].position
.y
= 0.0f
;
4926 vertices
[vertex
].position
.z
= z
;
4927 vertices
[vertex
].normal
.x
= 0.0f
;
4928 vertices
[vertex
].normal
.y
= 0.0f
;
4929 vertices
[vertex
].normal
.z
= 1.0f
;
4931 faces
[face
][0] = vertex_index(slices
, slice
-1, stack
);
4932 faces
[face
][1] = number_of_vertices
- 1;
4933 faces
[face
][2] = vertex_index(slices
, 0, stack
);
4935 free_sincos_table(&theta
);
4936 cylinder
->lpVtbl
->UnlockIndexBuffer(cylinder
);
4937 cylinder
->lpVtbl
->UnlockVertexBuffer(cylinder
);
4943 HRESULT WINAPI
D3DXCreateTeapot(struct IDirect3DDevice9
*device
,
4944 struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
)
4946 FIXME("(%p, %p, %p): stub\n", device
, mesh
, adjacency
);
4951 HRESULT WINAPI
D3DXCreateTextA(struct IDirect3DDevice9
*device
, HDC hdc
, const char *text
, float deviation
,
4952 float extrusion
, struct ID3DXMesh
**mesh
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
4958 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
4959 debugstr_a(text
), deviation
, extrusion
, mesh
, adjacency
, glyphmetrics
);
4962 return D3DERR_INVALIDCALL
;
4964 len
= MultiByteToWideChar(CP_ACP
, 0, text
, -1, NULL
, 0);
4965 textW
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
4966 MultiByteToWideChar(CP_ACP
, 0, text
, -1, textW
, len
);
4968 hr
= D3DXCreateTextW(device
, hdc
, textW
, deviation
, extrusion
,
4969 mesh
, adjacency
, glyphmetrics
);
4970 HeapFree(GetProcessHeap(), 0, textW
);
4976 POINTTYPE_CURVE
= 0,
4978 POINTTYPE_CURVE_START
,
4979 POINTTYPE_CURVE_END
,
4980 POINTTYPE_CURVE_MIDDLE
,
4986 enum pointtype corner
;
4989 struct dynamic_array
4991 int count
, capacity
;
4995 /* is a dynamic_array */
4998 int count
, capacity
;
4999 struct point2d
*items
;
5002 /* is a dynamic_array */
5003 struct outline_array
5005 int count
, capacity
;
5006 struct outline
*items
;
5015 struct point2d_index
5017 struct outline
*outline
;
5021 struct point2d_index_array
5024 struct point2d_index
*items
;
5029 struct outline_array outlines
;
5030 struct face_array faces
;
5031 struct point2d_index_array ordered_vertices
;
5035 /* is an dynamic_array */
5038 int count
, capacity
;
5042 /* complex polygons are split into monotone polygons, which have
5043 * at most 2 intersections with the vertical sweep line */
5044 struct triangulation
5046 struct word_array vertex_stack
;
5047 BOOL last_on_top
, merging
;
5050 /* is an dynamic_array */
5051 struct triangulation_array
5053 int count
, capacity
;
5054 struct triangulation
*items
;
5056 struct glyphinfo
*glyph
;
5059 static BOOL
reserve(struct dynamic_array
*array
, int count
, int itemsize
)
5061 if (count
> array
->capacity
) {
5064 if (array
->items
&& array
->capacity
) {
5065 new_capacity
= max(array
->capacity
* 2, count
);
5066 new_buffer
= HeapReAlloc(GetProcessHeap(), 0, array
->items
, new_capacity
* itemsize
);
5068 new_capacity
= max(16, count
);
5069 new_buffer
= HeapAlloc(GetProcessHeap(), 0, new_capacity
* itemsize
);
5073 array
->items
= new_buffer
;
5074 array
->capacity
= new_capacity
;
5079 static struct point2d
*add_points(struct outline
*array
, int num
)
5081 struct point2d
*item
;
5083 if (!reserve((struct dynamic_array
*)array
, array
->count
+ num
, sizeof(array
->items
[0])))
5086 item
= &array
->items
[array
->count
];
5087 array
->count
+= num
;
5091 static struct outline
*add_outline(struct outline_array
*array
)
5093 struct outline
*item
;
5095 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5098 item
= &array
->items
[array
->count
++];
5099 ZeroMemory(item
, sizeof(*item
));
5103 static inline face
*add_face(struct face_array
*array
)
5105 return &array
->items
[array
->count
++];
5108 static struct triangulation
*add_triangulation(struct triangulation_array
*array
)
5110 struct triangulation
*item
;
5112 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5115 item
= &array
->items
[array
->count
++];
5116 ZeroMemory(item
, sizeof(*item
));
5120 static HRESULT
add_vertex_index(struct word_array
*array
, WORD vertex_index
)
5122 if (!reserve((struct dynamic_array
*)array
, array
->count
+ 1, sizeof(array
->items
[0])))
5123 return E_OUTOFMEMORY
;
5125 array
->items
[array
->count
++] = vertex_index
;
5129 /* assume fixed point numbers can be converted to float point in place */
5130 C_ASSERT(sizeof(FIXED
) == sizeof(float));
5131 C_ASSERT(sizeof(POINTFX
) == sizeof(D3DXVECTOR2
));
5133 static inline D3DXVECTOR2
*convert_fixed_to_float(POINTFX
*pt
, int count
, float emsquare
)
5135 D3DXVECTOR2
*ret
= (D3DXVECTOR2
*)pt
;
5137 D3DXVECTOR2
*pt_flt
= (D3DXVECTOR2
*)pt
;
5138 pt_flt
->x
= (pt
->x
.value
+ pt
->x
.fract
/ (float)0x10000) / emsquare
;
5139 pt_flt
->y
= (pt
->y
.value
+ pt
->y
.fract
/ (float)0x10000) / emsquare
;
5145 static HRESULT
add_bezier_points(struct outline
*outline
, const D3DXVECTOR2
*p1
,
5146 const D3DXVECTOR2
*p2
, const D3DXVECTOR2
*p3
,
5147 float max_deviation_sq
)
5149 D3DXVECTOR2 split1
= {0, 0}, split2
= {0, 0}, middle
, vec
;
5152 D3DXVec2Scale(&split1
, D3DXVec2Add(&split1
, p1
, p2
), 0.5f
);
5153 D3DXVec2Scale(&split2
, D3DXVec2Add(&split2
, p2
, p3
), 0.5f
);
5154 D3DXVec2Scale(&middle
, D3DXVec2Add(&middle
, &split1
, &split2
), 0.5f
);
5156 deviation_sq
= D3DXVec2LengthSq(D3DXVec2Subtract(&vec
, &middle
, p2
));
5157 if (deviation_sq
< max_deviation_sq
) {
5158 struct point2d
*pt
= add_points(outline
, 1);
5159 if (!pt
) return E_OUTOFMEMORY
;
5161 pt
->corner
= POINTTYPE_CURVE
;
5162 /* the end point is omitted because the end line merges into the next segment of
5163 * the split bezier curve, and the end of the split bezier curve is added outside
5164 * this recursive function. */
5166 HRESULT hr
= add_bezier_points(outline
, p1
, &split1
, &middle
, max_deviation_sq
);
5167 if (hr
!= S_OK
) return hr
;
5168 hr
= add_bezier_points(outline
, &middle
, &split2
, p3
, max_deviation_sq
);
5169 if (hr
!= S_OK
) return hr
;
5175 static inline BOOL
is_direction_similar(D3DXVECTOR2
*dir1
, D3DXVECTOR2
*dir2
, float cos_theta
)
5177 /* dot product = cos(theta) */
5178 return D3DXVec2Dot(dir1
, dir2
) > cos_theta
;
5181 static inline D3DXVECTOR2
*unit_vec2(D3DXVECTOR2
*dir
, const D3DXVECTOR2
*pt1
, const D3DXVECTOR2
*pt2
)
5183 return D3DXVec2Normalize(D3DXVec2Subtract(dir
, pt2
, pt1
), dir
);
5193 static BOOL
attempt_line_merge(struct outline
*outline
,
5195 const D3DXVECTOR2
*nextpt
,
5197 const struct cos_table
*table
)
5199 D3DXVECTOR2 curdir
, lastdir
;
5200 struct point2d
*prevpt
, *pt
;
5203 pt
= &outline
->items
[pt_index
];
5204 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5205 prevpt
= &outline
->items
[pt_index
];
5208 pt
->corner
= pt
->corner
!= POINTTYPE_CORNER
? POINTTYPE_CURVE_MIDDLE
: POINTTYPE_CURVE_START
;
5210 if (outline
->count
< 2)
5213 /* remove last point if the next line continues the last line */
5214 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5215 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5216 if (is_direction_similar(&lastdir
, &curdir
, table
->cos_half
))
5219 if (pt
->corner
== POINTTYPE_CURVE_END
)
5220 prevpt
->corner
= pt
->corner
;
5221 if (prevpt
->corner
== POINTTYPE_CURVE_END
&& to_curve
)
5222 prevpt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5226 if (outline
->count
< 2)
5229 pt_index
= (pt_index
- 1 + outline
->count
) % outline
->count
;
5230 prevpt
= &outline
->items
[pt_index
];
5231 unit_vec2(&lastdir
, &prevpt
->pos
, &pt
->pos
);
5232 unit_vec2(&curdir
, &pt
->pos
, nextpt
);
5237 static HRESULT
create_outline(struct glyphinfo
*glyph
, void *raw_outline
, int datasize
,
5238 float max_deviation_sq
, float emsquare
, const struct cos_table
*cos_table
)
5240 TTPOLYGONHEADER
*header
= (TTPOLYGONHEADER
*)raw_outline
;
5242 while ((char *)header
< (char *)raw_outline
+ datasize
)
5244 TTPOLYCURVE
*curve
= (TTPOLYCURVE
*)(header
+ 1);
5245 struct point2d
*lastpt
, *pt
;
5246 D3DXVECTOR2 lastdir
;
5247 D3DXVECTOR2
*pt_flt
;
5249 struct outline
*outline
= add_outline(&glyph
->outlines
);
5252 return E_OUTOFMEMORY
;
5254 pt
= add_points(outline
, 1);
5256 return E_OUTOFMEMORY
;
5257 pt_flt
= convert_fixed_to_float(&header
->pfxStart
, 1, emsquare
);
5259 pt
->corner
= POINTTYPE_CORNER
;
5261 if (header
->dwType
!= TT_POLYGON_TYPE
)
5262 FIXME("Unknown header type %d\n", header
->dwType
);
5264 while ((char *)curve
< (char *)header
+ header
->cb
)
5266 D3DXVECTOR2 bezier_start
= outline
->items
[outline
->count
- 1].pos
;
5267 BOOL to_curve
= curve
->wType
!= TT_PRIM_LINE
&& curve
->cpfx
> 1;
5268 unsigned int j2
= 0;
5271 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5275 pt_flt
= convert_fixed_to_float(curve
->apfx
, curve
->cpfx
, emsquare
);
5277 attempt_line_merge(outline
, outline
->count
- 1, &pt_flt
[0], to_curve
, cos_table
);
5282 int count
= curve
->cpfx
;
5286 D3DXVECTOR2 bezier_end
;
5288 D3DXVec2Scale(&bezier_end
, D3DXVec2Add(&bezier_end
, &pt_flt
[j2
], &pt_flt
[j2
+1]), 0.5f
);
5289 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &bezier_end
, max_deviation_sq
);
5292 bezier_start
= bezier_end
;
5296 hr
= add_bezier_points(outline
, &bezier_start
, &pt_flt
[j2
], &pt_flt
[j2
+1], max_deviation_sq
);
5300 pt
= add_points(outline
, 1);
5302 return E_OUTOFMEMORY
;
5304 pt
->pos
= pt_flt
[j2
];
5305 pt
->corner
= POINTTYPE_CURVE_END
;
5307 pt
= add_points(outline
, curve
->cpfx
);
5309 return E_OUTOFMEMORY
;
5310 for (j2
= 0; j2
< curve
->cpfx
; j2
++)
5312 pt
->pos
= pt_flt
[j2
];
5313 pt
->corner
= POINTTYPE_CORNER
;
5318 curve
= (TTPOLYCURVE
*)&curve
->apfx
[curve
->cpfx
];
5321 /* remove last point if the next line continues the last line */
5322 if (outline
->count
>= 3) {
5325 lastpt
= &outline
->items
[outline
->count
- 1];
5326 pt
= &outline
->items
[0];
5327 if (pt
->pos
.x
== lastpt
->pos
.x
&& pt
->pos
.y
== lastpt
->pos
.y
) {
5328 if (lastpt
->corner
== POINTTYPE_CURVE_END
)
5330 if (pt
->corner
== POINTTYPE_CURVE_START
)
5331 pt
->corner
= POINTTYPE_CURVE_MIDDLE
;
5333 pt
->corner
= POINTTYPE_CURVE_END
;
5336 lastpt
= &outline
->items
[outline
->count
- 1];
5338 /* outline closed with a line from end to start point */
5339 attempt_line_merge(outline
, outline
->count
- 1, &pt
->pos
, FALSE
, cos_table
);
5341 lastpt
= &outline
->items
[0];
5342 to_curve
= lastpt
->corner
!= POINTTYPE_CORNER
&& lastpt
->corner
!= POINTTYPE_CURVE_END
;
5343 if (lastpt
->corner
== POINTTYPE_CURVE_START
)
5344 lastpt
->corner
= POINTTYPE_CORNER
;
5345 pt
= &outline
->items
[1];
5346 if (attempt_line_merge(outline
, 0, &pt
->pos
, to_curve
, cos_table
))
5347 *lastpt
= outline
->items
[outline
->count
];
5350 lastpt
= &outline
->items
[outline
->count
- 1];
5351 pt
= &outline
->items
[0];
5352 unit_vec2(&lastdir
, &lastpt
->pos
, &pt
->pos
);
5353 for (j
= 0; j
< outline
->count
; j
++)
5358 pt
= &outline
->items
[(j
+ 1) % outline
->count
];
5359 unit_vec2(&curdir
, &lastpt
->pos
, &pt
->pos
);
5361 switch (lastpt
->corner
)
5363 case POINTTYPE_CURVE_START
:
5364 case POINTTYPE_CURVE_END
:
5365 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_45
))
5366 lastpt
->corner
= POINTTYPE_CORNER
;
5368 case POINTTYPE_CURVE_MIDDLE
:
5369 if (!is_direction_similar(&lastdir
, &curdir
, cos_table
->cos_90
))
5370 lastpt
->corner
= POINTTYPE_CORNER
;
5372 lastpt
->corner
= POINTTYPE_CURVE
;
5380 header
= (TTPOLYGONHEADER
*)((char *)header
+ header
->cb
);
5385 /* Get the y-distance from a line to a point */
5386 static float get_line_to_point_y_distance(D3DXVECTOR2
*line_pt1
,
5387 D3DXVECTOR2
*line_pt2
,
5390 D3DXVECTOR2 line_vec
= {0, 0};
5394 D3DXVec2Subtract(&line_vec
, line_pt2
, line_pt1
);
5395 line_pt_dx
= point
->x
- line_pt1
->x
;
5396 line_y
= line_pt1
->y
+ (line_vec
.y
* line_pt_dx
) / line_vec
.x
;
5397 return point
->y
- line_y
;
5400 static D3DXVECTOR2
*get_indexed_point(struct point2d_index
*pt_idx
)
5402 return &pt_idx
->outline
->items
[pt_idx
->vertex
].pos
;
5405 static D3DXVECTOR2
*get_ordered_vertex(struct glyphinfo
*glyph
, WORD index
)
5407 return get_indexed_point(&glyph
->ordered_vertices
.items
[index
]);
5410 static void remove_triangulation(struct triangulation_array
*array
, struct triangulation
*item
)
5412 HeapFree(GetProcessHeap(), 0, item
->vertex_stack
.items
);
5413 MoveMemory(item
, item
+ 1, (char*)&array
->items
[array
->count
] - (char*)(item
+ 1));
5417 static HRESULT
triangulation_add_point(struct triangulation
**t_ptr
,
5418 struct triangulation_array
*triangulations
,
5422 struct glyphinfo
*glyph
= triangulations
->glyph
;
5423 struct triangulation
*t
= *t_ptr
;
5428 if (t
->last_on_top
) {
5436 if (t
->last_on_top
!= to_top
&& t
->vertex_stack
.count
> 1) {
5437 /* consume all vertices on the stack */
5438 WORD last_pt
= t
->vertex_stack
.items
[0];
5440 for (i
= 1; i
< t
->vertex_stack
.count
; i
++)
5442 face
= add_face(&glyph
->faces
);
5443 if (!face
) return E_OUTOFMEMORY
;
5444 (*face
)[0] = vtx_idx
;
5445 (*face
)[f1
] = last_pt
;
5446 (*face
)[f2
] = last_pt
= t
->vertex_stack
.items
[i
];
5448 t
->vertex_stack
.items
[0] = last_pt
;
5449 t
->vertex_stack
.count
= 1;
5450 } else if (t
->vertex_stack
.count
> 1) {
5451 int i
= t
->vertex_stack
.count
- 1;
5452 D3DXVECTOR2
*point
= get_ordered_vertex(glyph
, vtx_idx
);
5453 WORD top_idx
= t
->vertex_stack
.items
[i
--];
5454 D3DXVECTOR2
*top_pt
= get_ordered_vertex(glyph
, top_idx
);
5458 WORD prev_idx
= t
->vertex_stack
.items
[i
--];
5459 D3DXVECTOR2
*prev_pt
= get_ordered_vertex(glyph
, prev_idx
);
5461 if (prev_pt
->x
!= top_pt
->x
&&
5462 ((to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) > 0) ||
5463 (!to_top
&& get_line_to_point_y_distance(prev_pt
, top_pt
, point
) < 0)))
5466 face
= add_face(&glyph
->faces
);
5467 if (!face
) return E_OUTOFMEMORY
;
5468 (*face
)[0] = vtx_idx
;
5469 (*face
)[f1
] = prev_idx
;
5470 (*face
)[f2
] = top_idx
;
5474 t
->vertex_stack
.count
--;
5477 t
->last_on_top
= to_top
;
5479 hr
= add_vertex_index(&t
->vertex_stack
, vtx_idx
);
5481 if (hr
== S_OK
&& t
->merging
) {
5482 struct triangulation
*t2
;
5484 t2
= to_top
? t
- 1 : t
+ 1;
5485 t2
->merging
= FALSE
;
5486 hr
= triangulation_add_point(&t2
, triangulations
, vtx_idx
, to_top
);
5487 if (hr
!= S_OK
) return hr
;
5488 remove_triangulation(triangulations
, t
);
5496 /* check if the point is next on the outline for either the top or bottom */
5497 static D3DXVECTOR2
*triangulation_get_next_point(struct triangulation
*t
, struct glyphinfo
*glyph
, BOOL on_top
)
5499 int i
= t
->last_on_top
== on_top
? t
->vertex_stack
.count
- 1 : 0;
5500 WORD idx
= t
->vertex_stack
.items
[i
];
5501 struct point2d_index
*pt_idx
= &glyph
->ordered_vertices
.items
[idx
];
5502 struct outline
*outline
= pt_idx
->outline
;
5505 i
= (pt_idx
->vertex
+ outline
->count
- 1) % outline
->count
;
5507 i
= (pt_idx
->vertex
+ 1) % outline
->count
;
5509 return &outline
->items
[i
].pos
;
5512 static int compare_vertex_indices(const void *a
, const void *b
)
5514 const struct point2d_index
*idx1
= a
, *idx2
= b
;
5515 const D3DXVECTOR2
*p1
= &idx1
->outline
->items
[idx1
->vertex
].pos
;
5516 const D3DXVECTOR2
*p2
= &idx2
->outline
->items
[idx2
->vertex
].pos
;
5517 float diff
= p1
->x
- p2
->x
;
5520 diff
= p1
->y
- p2
->y
;
5522 return diff
== 0.0f
? 0 : (diff
> 0.0f
? -1 : 1);
5525 static HRESULT
triangulate(struct triangulation_array
*triangulations
)
5529 struct glyphinfo
*glyph
= triangulations
->glyph
;
5530 int nb_vertices
= 0;
5532 struct point2d_index
*idx_ptr
;
5534 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5535 nb_vertices
+= glyph
->outlines
.items
[i
].count
;
5537 glyph
->ordered_vertices
.items
= HeapAlloc(GetProcessHeap(), 0,
5538 nb_vertices
* sizeof(*glyph
->ordered_vertices
.items
));
5539 if (!glyph
->ordered_vertices
.items
)
5540 return E_OUTOFMEMORY
;
5542 idx_ptr
= glyph
->ordered_vertices
.items
;
5543 for (i
= 0; i
< glyph
->outlines
.count
; i
++)
5545 struct outline
*outline
= &glyph
->outlines
.items
[i
];
5548 idx_ptr
->outline
= outline
;
5549 idx_ptr
->vertex
= 0;
5551 for (j
= outline
->count
- 1; j
> 0; j
--)
5553 idx_ptr
->outline
= outline
;
5554 idx_ptr
->vertex
= j
;
5558 glyph
->ordered_vertices
.count
= nb_vertices
;
5560 /* Native implementation seems to try to create a triangle fan from
5561 * the first outline point if the glyph only has one outline. */
5562 if (glyph
->outlines
.count
== 1)
5564 struct outline
*outline
= glyph
->outlines
.items
;
5565 D3DXVECTOR2
*base
= &outline
->items
[0].pos
;
5566 D3DXVECTOR2
*last
= &outline
->items
[1].pos
;
5569 for (i
= 2; i
< outline
->count
; i
++)
5571 D3DXVECTOR2
*next
= &outline
->items
[i
].pos
;
5572 D3DXVECTOR2 v1
= {0.0f
, 0.0f
};
5573 D3DXVECTOR2 v2
= {0.0f
, 0.0f
};
5575 D3DXVec2Subtract(&v1
, base
, last
);
5576 D3DXVec2Subtract(&v2
, last
, next
);
5577 ccw
= D3DXVec2CCW(&v1
, &v2
);
5585 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5586 (outline
->count
- 2) * sizeof(glyph
->faces
.items
[0]));
5587 if (!glyph
->faces
.items
)
5588 return E_OUTOFMEMORY
;
5590 glyph
->faces
.count
= outline
->count
- 2;
5591 for (i
= 0; i
< glyph
->faces
.count
; i
++)
5593 glyph
->faces
.items
[i
][0] = 0;
5594 glyph
->faces
.items
[i
][1] = i
+ 1;
5595 glyph
->faces
.items
[i
][2] = i
+ 2;
5601 /* Perform 2D polygon triangulation for complex glyphs.
5602 * Triangulation is performed using a sweep line concept, from right to left,
5603 * by processing vertices in sorted order. Complex polygons are split into
5604 * monotone polygons which are triangulated separately. */
5605 /* FIXME: The order of the faces is not consistent with the native implementation. */
5607 /* Reserve space for maximum possible faces from triangulation.
5608 * # faces for outer outlines = outline->count - 2
5609 * # faces for inner outlines = outline->count + 2
5610 * There must be at least 1 outer outline. */
5611 glyph
->faces
.items
= HeapAlloc(GetProcessHeap(), 0,
5612 (nb_vertices
+ glyph
->outlines
.count
* 2 - 4) * sizeof(glyph
->faces
.items
[0]));
5613 if (!glyph
->faces
.items
)
5614 return E_OUTOFMEMORY
;
5616 qsort(glyph
->ordered_vertices
.items
, nb_vertices
,
5617 sizeof(glyph
->ordered_vertices
.items
[0]), compare_vertex_indices
);
5618 for (sweep_idx
= 0; sweep_idx
< glyph
->ordered_vertices
.count
; sweep_idx
++)
5621 int end
= triangulations
->count
;
5625 D3DXVECTOR2
*sweep_vtx
= get_ordered_vertex(glyph
, sweep_idx
);
5626 int current
= (start
+ end
) / 2;
5627 struct triangulation
*t
= &triangulations
->items
[current
];
5628 BOOL on_top_outline
= FALSE
;
5629 D3DXVECTOR2
*top_next
, *bottom_next
;
5630 WORD top_idx
, bottom_idx
;
5632 if (t
->merging
&& t
->last_on_top
)
5633 top_next
= triangulation_get_next_point(t
+ 1, glyph
, TRUE
);
5635 top_next
= triangulation_get_next_point(t
, glyph
, TRUE
);
5636 if (sweep_vtx
== top_next
)
5638 if (t
->merging
&& t
->last_on_top
)
5640 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, TRUE
);
5641 if (hr
!= S_OK
) return hr
;
5643 if (t
+ 1 < &triangulations
->items
[triangulations
->count
] &&
5644 triangulation_get_next_point(t
+ 1, glyph
, FALSE
) == sweep_vtx
)
5646 /* point also on bottom outline of higher triangulation */
5647 struct triangulation
*t2
= t
+ 1;
5648 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, FALSE
);
5649 if (hr
!= S_OK
) return hr
;
5654 on_top_outline
= TRUE
;
5657 if (t
->merging
&& !t
->last_on_top
)
5658 bottom_next
= triangulation_get_next_point(t
- 1, glyph
, FALSE
);
5660 bottom_next
= triangulation_get_next_point(t
, glyph
, FALSE
);
5661 if (sweep_vtx
== bottom_next
)
5663 if (t
->merging
&& !t
->last_on_top
)
5665 if (on_top_outline
) {
5666 /* outline finished */
5667 remove_triangulation(triangulations
, t
);
5671 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, FALSE
);
5672 if (hr
!= S_OK
) return hr
;
5674 if (t
> triangulations
->items
&&
5675 triangulation_get_next_point(t
- 1, glyph
, TRUE
) == sweep_vtx
)
5677 struct triangulation
*t2
= t
- 1;
5678 /* point also on top outline of lower triangulation */
5679 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, TRUE
);
5680 if (hr
!= S_OK
) return hr
;
5681 t
= t2
+ 1; /* t may be invalidated by triangulation merging */
5691 if (t
->last_on_top
) {
5692 top_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5693 bottom_idx
= t
->vertex_stack
.items
[0];
5695 top_idx
= t
->vertex_stack
.items
[0];
5696 bottom_idx
= t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1];
5699 /* check if the point is inside or outside this polygon */
5700 if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, top_idx
),
5701 top_next
, sweep_vtx
) > 0)
5703 start
= current
+ 1;
5704 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph
, bottom_idx
),
5705 bottom_next
, sweep_vtx
) < 0)
5708 } else if (t
->merging
) {
5709 /* inside, so cancel merging */
5710 struct triangulation
*t2
= t
->last_on_top
? t
+ 1 : t
- 1;
5712 t2
->merging
= FALSE
;
5713 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5714 if (hr
!= S_OK
) return hr
;
5715 hr
= triangulation_add_point(&t2
, triangulations
, sweep_idx
, t2
->last_on_top
);
5716 if (hr
!= S_OK
) return hr
;
5719 /* inside, so split polygon into two monotone parts */
5720 struct triangulation
*t2
= add_triangulation(triangulations
);
5721 if (!t2
) return E_OUTOFMEMORY
;
5722 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5723 if (t
->last_on_top
) {
5730 ZeroMemory(&t2
->vertex_stack
, sizeof(t2
->vertex_stack
));
5731 hr
= add_vertex_index(&t2
->vertex_stack
, t
->vertex_stack
.items
[t
->vertex_stack
.count
- 1]);
5732 if (hr
!= S_OK
) return hr
;
5733 hr
= add_vertex_index(&t2
->vertex_stack
, sweep_idx
);
5734 if (hr
!= S_OK
) return hr
;
5735 t2
->last_on_top
= !t
->last_on_top
;
5737 hr
= triangulation_add_point(&t
, triangulations
, sweep_idx
, t
->last_on_top
);
5738 if (hr
!= S_OK
) return hr
;
5744 struct triangulation
*t
;
5745 struct triangulation
*t2
= add_triangulation(triangulations
);
5746 if (!t2
) return E_OUTOFMEMORY
;
5747 t
= &triangulations
->items
[start
];
5748 MoveMemory(t
+ 1, t
, (char*)(t2
+ 1) - (char*)t
);
5749 ZeroMemory(t
, sizeof(*t
));
5750 hr
= add_vertex_index(&t
->vertex_stack
, sweep_idx
);
5751 if (hr
!= S_OK
) return hr
;
5757 HRESULT WINAPI
D3DXCreateTextW(struct IDirect3DDevice9
*device
, HDC hdc
, const WCHAR
*text
, float deviation
,
5758 float extrusion
, struct ID3DXMesh
**mesh_ptr
, struct ID3DXBuffer
**adjacency
, GLYPHMETRICSFLOAT
*glyphmetrics
)
5761 ID3DXMesh
*mesh
= NULL
;
5762 DWORD nb_vertices
, nb_faces
;
5763 DWORD nb_front_faces
, nb_corners
, nb_outline_points
;
5764 struct vertex
*vertices
= NULL
;
5769 OUTLINETEXTMETRICW otm
;
5770 HFONT font
= NULL
, oldfont
= NULL
;
5771 const MAT2 identity
= {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
5772 void *raw_outline
= NULL
;
5774 struct glyphinfo
*glyphs
= NULL
;
5776 struct triangulation_array triangulations
= {0, 0, NULL
};
5778 struct vertex
*vertex_ptr
;
5780 float max_deviation_sq
;
5781 const struct cos_table cos_table
= {
5782 cos(D3DXToRadian(0.5f
)),
5783 cos(D3DXToRadian(45.0f
)),
5784 cos(D3DXToRadian(90.0f
)),
5788 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device
, hdc
,
5789 debugstr_w(text
), deviation
, extrusion
, mesh_ptr
, adjacency
, glyphmetrics
);
5791 if (!device
|| !hdc
|| !text
|| !*text
|| deviation
< 0.0f
|| extrusion
< 0.0f
|| !mesh_ptr
)
5792 return D3DERR_INVALIDCALL
;
5796 FIXME("Case of adjacency != NULL not implemented.\n");
5800 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
) ||
5801 !GetOutlineTextMetricsW(hdc
, sizeof(otm
), &otm
))
5803 return D3DERR_INVALIDCALL
;
5806 if (deviation
== 0.0f
)
5807 deviation
= 1.0f
/ otm
.otmEMSquare
;
5808 max_deviation_sq
= deviation
* deviation
;
5810 lf
.lfHeight
= otm
.otmEMSquare
;
5812 font
= CreateFontIndirectW(&lf
);
5817 oldfont
= SelectObject(hdc
, font
);
5819 textlen
= strlenW(text
);
5820 for (i
= 0; i
< textlen
; i
++)
5822 int datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, 0, NULL
, &identity
);
5824 return D3DERR_INVALIDCALL
;
5825 if (bufsize
< datasize
)
5828 if (!bufsize
) { /* e.g. text == " " */
5829 hr
= D3DERR_INVALIDCALL
;
5833 glyphs
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, textlen
* sizeof(*glyphs
));
5834 raw_outline
= HeapAlloc(GetProcessHeap(), 0, bufsize
);
5835 if (!glyphs
|| !raw_outline
) {
5841 for (i
= 0; i
< textlen
; i
++)
5843 /* get outline points from data returned from GetGlyphOutline */
5846 glyphs
[i
].offset_x
= offset_x
;
5848 datasize
= GetGlyphOutlineW(hdc
, text
[i
], GGO_NATIVE
, &gm
, bufsize
, raw_outline
, &identity
);
5849 hr
= create_outline(&glyphs
[i
], raw_outline
, datasize
,
5850 max_deviation_sq
, otm
.otmEMSquare
, &cos_table
);
5851 if (hr
!= S_OK
) goto error
;
5853 triangulations
.glyph
= &glyphs
[i
];
5854 hr
= triangulate(&triangulations
);
5855 if (hr
!= S_OK
) goto error
;
5856 if (triangulations
.count
) {
5857 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations
.count
, text
[i
]);
5858 triangulations
.count
= 0;
5863 glyphmetrics
[i
].gmfBlackBoxX
= gm
.gmBlackBoxX
/ (float)otm
.otmEMSquare
;
5864 glyphmetrics
[i
].gmfBlackBoxY
= gm
.gmBlackBoxY
/ (float)otm
.otmEMSquare
;
5865 glyphmetrics
[i
].gmfptGlyphOrigin
.x
= gm
.gmptGlyphOrigin
.x
/ (float)otm
.otmEMSquare
;
5866 glyphmetrics
[i
].gmfptGlyphOrigin
.y
= gm
.gmptGlyphOrigin
.y
/ (float)otm
.otmEMSquare
;
5867 glyphmetrics
[i
].gmfCellIncX
= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5868 glyphmetrics
[i
].gmfCellIncY
= gm
.gmCellIncY
/ (float)otm
.otmEMSquare
;
5870 offset_x
+= gm
.gmCellIncX
/ (float)otm
.otmEMSquare
;
5873 /* corner points need an extra vertex for the different side faces normals */
5875 nb_outline_points
= 0;
5877 for (i
= 0; i
< textlen
; i
++)
5880 nb_outline_points
+= glyphs
[i
].ordered_vertices
.count
;
5881 nb_front_faces
+= glyphs
[i
].faces
.count
;
5882 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5885 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5886 nb_corners
++; /* first outline point always repeated as a corner */
5887 for (k
= 1; k
< outline
->count
; k
++)
5888 if (outline
->items
[k
].corner
)
5893 nb_vertices
= (nb_outline_points
+ nb_corners
) * 2 + nb_outline_points
* 2;
5894 nb_faces
= nb_outline_points
* 2 + nb_front_faces
* 2;
5897 hr
= D3DXCreateMeshFVF(nb_faces
, nb_vertices
, D3DXMESH_MANAGED
,
5898 D3DFVF_XYZ
| D3DFVF_NORMAL
, device
, &mesh
);
5902 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (LPVOID
*)&vertices
);
5906 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, (LPVOID
*)&faces
);
5910 /* convert 2D vertices and faces into 3D mesh */
5911 vertex_ptr
= vertices
;
5913 if (extrusion
== 0.0f
) {
5920 for (i
= 0; i
< textlen
; i
++)
5924 struct vertex
*back_vertices
;
5927 /* side vertices and faces */
5928 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
5930 struct vertex
*outline_vertices
= vertex_ptr
;
5931 struct outline
*outline
= &glyphs
[i
].outlines
.items
[j
];
5933 struct point2d
*prevpt
= &outline
->items
[outline
->count
- 1];
5934 struct point2d
*pt
= &outline
->items
[0];
5936 for (k
= 1; k
<= outline
->count
; k
++)
5939 struct point2d
*nextpt
= &outline
->items
[k
% outline
->count
];
5940 WORD vtx_idx
= vertex_ptr
- vertices
;
5943 if (pt
->corner
== POINTTYPE_CURVE_START
)
5944 D3DXVec2Subtract(&vec
, &pt
->pos
, &prevpt
->pos
);
5945 else if (pt
->corner
)
5946 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5948 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &prevpt
->pos
);
5949 D3DXVec2Normalize(&vec
, &vec
);
5950 vtx
.normal
.x
= -vec
.y
;
5951 vtx
.normal
.y
= vec
.x
;
5954 vtx
.position
.x
= pt
->pos
.x
+ glyphs
[i
].offset_x
;
5955 vtx
.position
.y
= pt
->pos
.y
;
5957 *vertex_ptr
++ = vtx
;
5959 vtx
.position
.z
= -extrusion
;
5960 *vertex_ptr
++ = vtx
;
5962 vtx
.position
.x
= nextpt
->pos
.x
+ glyphs
[i
].offset_x
;
5963 vtx
.position
.y
= nextpt
->pos
.y
;
5964 if (pt
->corner
&& nextpt
->corner
&& nextpt
->corner
!= POINTTYPE_CURVE_END
) {
5965 vtx
.position
.z
= -extrusion
;
5966 *vertex_ptr
++ = vtx
;
5968 *vertex_ptr
++ = vtx
;
5970 (*face_ptr
)[0] = vtx_idx
;
5971 (*face_ptr
)[1] = vtx_idx
+ 2;
5972 (*face_ptr
)[2] = vtx_idx
+ 1;
5975 (*face_ptr
)[0] = vtx_idx
;
5976 (*face_ptr
)[1] = vtx_idx
+ 3;
5977 (*face_ptr
)[2] = vtx_idx
+ 2;
5980 if (nextpt
->corner
) {
5981 if (nextpt
->corner
== POINTTYPE_CURVE_END
) {
5982 D3DXVECTOR2
*nextpt2
= &outline
->items
[(k
+ 1) % outline
->count
].pos
;
5983 D3DXVec2Subtract(&vec
, nextpt2
, &nextpt
->pos
);
5985 D3DXVec2Subtract(&vec
, &nextpt
->pos
, &pt
->pos
);
5987 D3DXVec2Normalize(&vec
, &vec
);
5988 vtx
.normal
.x
= -vec
.y
;
5989 vtx
.normal
.y
= vec
.x
;
5992 *vertex_ptr
++ = vtx
;
5993 vtx
.position
.z
= -extrusion
;
5994 *vertex_ptr
++ = vtx
;
5997 (*face_ptr
)[0] = vtx_idx
;
5998 (*face_ptr
)[1] = vtx_idx
+ 3;
5999 (*face_ptr
)[2] = vtx_idx
+ 1;
6002 (*face_ptr
)[0] = vtx_idx
;
6003 (*face_ptr
)[1] = vtx_idx
+ 2;
6004 (*face_ptr
)[2] = vtx_idx
+ 3;
6012 *vertex_ptr
++ = *outline_vertices
++;
6013 *vertex_ptr
++ = *outline_vertices
++;
6017 /* back vertices and faces */
6018 back_faces
= face_ptr
;
6019 back_vertices
= vertex_ptr
;
6020 for (j
= 0; j
< glyphs
[i
].ordered_vertices
.count
; j
++)
6022 D3DXVECTOR2
*pt
= get_ordered_vertex(&glyphs
[i
], j
);
6023 vertex_ptr
->position
.x
= pt
->x
+ glyphs
[i
].offset_x
;
6024 vertex_ptr
->position
.y
= pt
->y
;
6025 vertex_ptr
->position
.z
= 0;
6026 vertex_ptr
->normal
.x
= 0;
6027 vertex_ptr
->normal
.y
= 0;
6028 vertex_ptr
->normal
.z
= 1;
6031 count
= back_vertices
- vertices
;
6032 for (j
= 0; j
< glyphs
[i
].faces
.count
; j
++)
6034 face
*f
= &glyphs
[i
].faces
.items
[j
];
6035 (*face_ptr
)[0] = (*f
)[0] + count
;
6036 (*face_ptr
)[1] = (*f
)[1] + count
;
6037 (*face_ptr
)[2] = (*f
)[2] + count
;
6041 /* front vertices and faces */
6042 j
= count
= vertex_ptr
- back_vertices
;
6045 vertex_ptr
->position
.x
= back_vertices
->position
.x
;
6046 vertex_ptr
->position
.y
= back_vertices
->position
.y
;
6047 vertex_ptr
->position
.z
= -extrusion
;
6048 vertex_ptr
->normal
.x
= 0;
6049 vertex_ptr
->normal
.y
= 0;
6050 vertex_ptr
->normal
.z
= extrusion
== 0.0f
? 1.0f
: -1.0f
;
6054 j
= face_ptr
- back_faces
;
6057 (*face_ptr
)[0] = (*back_faces
)[0] + count
;
6058 (*face_ptr
)[1] = (*back_faces
)[f1
] + count
;
6059 (*face_ptr
)[2] = (*back_faces
)[f2
] + count
;
6069 if (faces
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6070 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6071 if (hr
!= D3D_OK
) mesh
->lpVtbl
->Release(mesh
);
6074 for (i
= 0; i
< textlen
; i
++)
6077 for (j
= 0; j
< glyphs
[i
].outlines
.count
; j
++)
6078 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
[j
].items
);
6079 HeapFree(GetProcessHeap(), 0, glyphs
[i
].outlines
.items
);
6080 HeapFree(GetProcessHeap(), 0, glyphs
[i
].faces
.items
);
6081 HeapFree(GetProcessHeap(), 0, glyphs
[i
].ordered_vertices
.items
);
6083 HeapFree(GetProcessHeap(), 0, glyphs
);
6085 if (triangulations
.items
) {
6087 for (i
= 0; i
< triangulations
.count
; i
++)
6088 HeapFree(GetProcessHeap(), 0, triangulations
.items
[i
].vertex_stack
.items
);
6089 HeapFree(GetProcessHeap(), 0, triangulations
.items
);
6091 HeapFree(GetProcessHeap(), 0, raw_outline
);
6092 if (oldfont
) SelectObject(hdc
, oldfont
);
6093 if (font
) DeleteObject(font
);
6098 HRESULT WINAPI
D3DXValidMesh(ID3DXMesh
*mesh
, const DWORD
*adjacency
, ID3DXBuffer
**errors_and_warnings
)
6100 FIXME("(%p, %p, %p): stub\n", mesh
, adjacency
, *errors_and_warnings
);
6105 static BOOL
weld_float1(void *to
, void *from
, FLOAT epsilon
)
6110 if (fabsf(*v1
- *v2
) <= epsilon
)
6120 static BOOL
weld_float2(void *to
, void *from
, FLOAT epsilon
)
6122 D3DXVECTOR2
*v1
= to
;
6123 D3DXVECTOR2
*v2
= from
;
6124 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6125 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6126 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6128 if (max_abs_diff
<= epsilon
)
6130 memcpy(to
, from
, sizeof(D3DXVECTOR2
));
6138 static BOOL
weld_float3(void *to
, void *from
, FLOAT epsilon
)
6140 D3DXVECTOR3
*v1
= to
;
6141 D3DXVECTOR3
*v2
= from
;
6142 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6143 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6144 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6145 FLOAT max_abs_diff
= max(diff_x
, diff_y
);
6146 max_abs_diff
= max(diff_z
, max_abs_diff
);
6148 if (max_abs_diff
<= epsilon
)
6150 memcpy(to
, from
, sizeof(D3DXVECTOR3
));
6158 static BOOL
weld_float4(void *to
, void *from
, FLOAT epsilon
)
6160 D3DXVECTOR4
*v1
= to
;
6161 D3DXVECTOR4
*v2
= from
;
6162 FLOAT diff_x
= fabsf(v1
->x
- v2
->x
);
6163 FLOAT diff_y
= fabsf(v1
->y
- v2
->y
);
6164 FLOAT diff_z
= fabsf(v1
->z
- v2
->z
);
6165 FLOAT diff_w
= fabsf(v1
->w
- v2
->w
);
6166 FLOAT max_abs_diff
= fmax(diff_x
, diff_y
);
6167 max_abs_diff
= max(diff_z
, max_abs_diff
);
6168 max_abs_diff
= max(diff_w
, max_abs_diff
);
6170 if (max_abs_diff
<= epsilon
)
6172 memcpy(to
, from
, sizeof(D3DXVECTOR4
));
6180 static BOOL
weld_ubyte4(void *to
, void *from
, FLOAT epsilon
)
6184 BYTE truncated_epsilon
= (BYTE
)epsilon
;
6185 BYTE diff_x
= b1
[0] > b2
[0] ? b1
[0] - b2
[0] : b2
[0] - b1
[0];
6186 BYTE diff_y
= b1
[1] > b2
[1] ? b1
[1] - b2
[1] : b2
[1] - b1
[1];
6187 BYTE diff_z
= b1
[2] > b2
[2] ? b1
[2] - b2
[2] : b2
[2] - b1
[2];
6188 BYTE diff_w
= b1
[3] > b2
[3] ? b1
[3] - b2
[3] : b2
[3] - b1
[3];
6189 BYTE max_diff
= max(diff_x
, diff_y
);
6190 max_diff
= max(diff_z
, max_diff
);
6191 max_diff
= max(diff_w
, max_diff
);
6193 if (max_diff
<= truncated_epsilon
)
6195 memcpy(to
, from
, 4 * sizeof(BYTE
));
6203 static BOOL
weld_ubyte4n(void *to
, void *from
, FLOAT epsilon
)
6205 return weld_ubyte4(to
, from
, epsilon
* UCHAR_MAX
);
6208 static BOOL
weld_d3dcolor(void *to
, void *from
, FLOAT epsilon
)
6210 return weld_ubyte4n(to
, from
, epsilon
);
6213 static BOOL
weld_short2(void *to
, void *from
, FLOAT epsilon
)
6217 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6218 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6219 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6220 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6222 if (max_abs_diff
<= truncated_epsilon
)
6224 memcpy(to
, from
, 2 * sizeof(SHORT
));
6232 static BOOL
weld_short2n(void *to
, void *from
, FLOAT epsilon
)
6234 return weld_short2(to
, from
, epsilon
* SHRT_MAX
);
6237 static BOOL
weld_short4(void *to
, void *from
, FLOAT epsilon
)
6241 SHORT truncated_epsilon
= (SHORT
)epsilon
;
6242 SHORT diff_x
= abs(s1
[0] - s2
[0]);
6243 SHORT diff_y
= abs(s1
[1] - s2
[1]);
6244 SHORT diff_z
= abs(s1
[2] - s2
[2]);
6245 SHORT diff_w
= abs(s1
[3] - s2
[3]);
6246 SHORT max_abs_diff
= max(diff_x
, diff_y
);
6247 max_abs_diff
= max(diff_z
, max_abs_diff
);
6248 max_abs_diff
= max(diff_w
, max_abs_diff
);
6250 if (max_abs_diff
<= truncated_epsilon
)
6252 memcpy(to
, from
, 4 * sizeof(SHORT
));
6260 static BOOL
weld_short4n(void *to
, void *from
, FLOAT epsilon
)
6262 return weld_short4(to
, from
, epsilon
* SHRT_MAX
);
6265 static BOOL
weld_ushort2n(void *to
, void *from
, FLOAT epsilon
)
6269 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6270 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6271 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6272 USHORT max_diff
= max(diff_x
, diff_y
);
6274 if (max_diff
<= scaled_epsilon
)
6276 memcpy(to
, from
, 2 * sizeof(USHORT
));
6284 static BOOL
weld_ushort4n(void *to
, void *from
, FLOAT epsilon
)
6288 USHORT scaled_epsilon
= (USHORT
)(epsilon
* USHRT_MAX
);
6289 USHORT diff_x
= s1
[0] > s2
[0] ? s1
[0] - s2
[0] : s2
[0] - s1
[0];
6290 USHORT diff_y
= s1
[1] > s2
[1] ? s1
[1] - s2
[1] : s2
[1] - s1
[1];
6291 USHORT diff_z
= s1
[2] > s2
[2] ? s1
[2] - s2
[2] : s2
[2] - s1
[2];
6292 USHORT diff_w
= s1
[3] > s2
[3] ? s1
[3] - s2
[3] : s2
[3] - s1
[3];
6293 USHORT max_diff
= max(diff_x
, diff_y
);
6294 max_diff
= max(diff_z
, max_diff
);
6295 max_diff
= max(diff_w
, max_diff
);
6297 if (max_diff
<= scaled_epsilon
)
6299 memcpy(to
, from
, 4 * sizeof(USHORT
));
6315 static struct udec3
dword_to_udec3(DWORD d
)
6320 v
.y
= (d
& 0xffc00) >> 10;
6321 v
.z
= (d
& 0x3ff00000) >> 20;
6322 v
.w
= (d
& 0xc0000000) >> 30;
6327 static BOOL
weld_udec3(void *to
, void *from
, FLOAT epsilon
)
6331 struct udec3 v1
= dword_to_udec3(*d1
);
6332 struct udec3 v2
= dword_to_udec3(*d2
);
6333 UINT truncated_epsilon
= (UINT
)epsilon
;
6334 UINT diff_x
= v1
.x
> v2
.x
? v1
.x
- v2
.x
: v2
.x
- v1
.x
;
6335 UINT diff_y
= v1
.y
> v2
.y
? v1
.y
- v2
.y
: v2
.y
- v1
.y
;
6336 UINT diff_z
= v1
.z
> v2
.z
? v1
.z
- v2
.z
: v2
.z
- v1
.z
;
6337 UINT diff_w
= v1
.w
> v2
.w
? v1
.w
- v2
.w
: v2
.w
- v1
.w
;
6338 UINT max_diff
= max(diff_x
, diff_y
);
6339 max_diff
= max(diff_z
, max_diff
);
6340 max_diff
= max(diff_w
, max_diff
);
6342 if (max_diff
<= truncated_epsilon
)
6344 memcpy(to
, from
, sizeof(DWORD
));
6360 static struct dec3n
dword_to_dec3n(DWORD d
)
6365 v
.y
= (d
& 0xffc00) >> 10;
6366 v
.z
= (d
& 0x3ff00000) >> 20;
6367 v
.w
= (d
& 0xc0000000) >> 30;
6372 static BOOL
weld_dec3n(void *to
, void *from
, FLOAT epsilon
)
6374 const UINT MAX_DEC3N
= 511;
6377 struct dec3n v1
= dword_to_dec3n(*d1
);
6378 struct dec3n v2
= dword_to_dec3n(*d2
);
6379 INT scaled_epsilon
= (INT
)(epsilon
* MAX_DEC3N
);
6380 INT diff_x
= abs(v1
.x
- v2
.x
);
6381 INT diff_y
= abs(v1
.y
- v2
.y
);
6382 INT diff_z
= abs(v1
.z
- v2
.z
);
6383 INT diff_w
= abs(v1
.w
- v2
.w
);
6384 INT max_abs_diff
= max(diff_x
, diff_y
);
6385 max_abs_diff
= max(diff_z
, max_abs_diff
);
6386 max_abs_diff
= max(diff_w
, max_abs_diff
);
6388 if (max_abs_diff
<= scaled_epsilon
)
6390 memcpy(to
, from
, sizeof(DWORD
));
6398 static BOOL
weld_float16_2(void *to
, void *from
, FLOAT epsilon
)
6400 D3DXFLOAT16
*v1_float16
= to
;
6401 D3DXFLOAT16
*v2_float16
= from
;
6405 const UINT NUM_ELEM
= 2;
6409 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6410 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6412 diff_x
= fabsf(v1
[0] - v2
[0]);
6413 diff_y
= fabsf(v1
[1] - v2
[1]);
6414 max_abs_diff
= max(diff_x
, diff_y
);
6416 if (max_abs_diff
<= epsilon
)
6418 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6426 static BOOL
weld_float16_4(void *to
, void *from
, FLOAT epsilon
)
6428 D3DXFLOAT16
*v1_float16
= to
;
6429 D3DXFLOAT16
*v2_float16
= from
;
6435 const UINT NUM_ELEM
= 4;
6439 D3DXFloat16To32Array(v1
, v1_float16
, NUM_ELEM
);
6440 D3DXFloat16To32Array(v2
, v2_float16
, NUM_ELEM
);
6442 diff_x
= fabsf(v1
[0] - v2
[0]);
6443 diff_y
= fabsf(v1
[1] - v2
[1]);
6444 diff_z
= fabsf(v1
[2] - v2
[2]);
6445 diff_w
= fabsf(v1
[3] - v2
[3]);
6446 max_abs_diff
= max(diff_x
, diff_y
);
6447 max_abs_diff
= max(diff_z
, max_abs_diff
);
6448 max_abs_diff
= max(diff_w
, max_abs_diff
);
6450 if (max_abs_diff
<= epsilon
)
6452 memcpy(to
, from
, NUM_ELEM
* sizeof(D3DXFLOAT16
));
6460 /* Sets the vertex components to the same value if they are within epsilon. */
6461 static BOOL
weld_component(void *to
, void *from
, D3DDECLTYPE type
, FLOAT epsilon
)
6463 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6464 BOOL fixme_once_unused
= FALSE
;
6465 BOOL fixme_once_unknown
= FALSE
;
6469 case D3DDECLTYPE_FLOAT1
:
6470 return weld_float1(to
, from
, epsilon
);
6472 case D3DDECLTYPE_FLOAT2
:
6473 return weld_float2(to
, from
, epsilon
);
6475 case D3DDECLTYPE_FLOAT3
:
6476 return weld_float3(to
, from
, epsilon
);
6478 case D3DDECLTYPE_FLOAT4
:
6479 return weld_float4(to
, from
, epsilon
);
6481 case D3DDECLTYPE_D3DCOLOR
:
6482 return weld_d3dcolor(to
, from
, epsilon
);
6484 case D3DDECLTYPE_UBYTE4
:
6485 return weld_ubyte4(to
, from
, epsilon
);
6487 case D3DDECLTYPE_SHORT2
:
6488 return weld_short2(to
, from
, epsilon
);
6490 case D3DDECLTYPE_SHORT4
:
6491 return weld_short4(to
, from
, epsilon
);
6493 case D3DDECLTYPE_UBYTE4N
:
6494 return weld_ubyte4n(to
, from
, epsilon
);
6496 case D3DDECLTYPE_SHORT2N
:
6497 return weld_short2n(to
, from
, epsilon
);
6499 case D3DDECLTYPE_SHORT4N
:
6500 return weld_short4n(to
, from
, epsilon
);
6502 case D3DDECLTYPE_USHORT2N
:
6503 return weld_ushort2n(to
, from
, epsilon
);
6505 case D3DDECLTYPE_USHORT4N
:
6506 return weld_ushort4n(to
, from
, epsilon
);
6508 case D3DDECLTYPE_UDEC3
:
6509 return weld_udec3(to
, from
, epsilon
);
6511 case D3DDECLTYPE_DEC3N
:
6512 return weld_dec3n(to
, from
, epsilon
);
6514 case D3DDECLTYPE_FLOAT16_2
:
6515 return weld_float16_2(to
, from
, epsilon
);
6517 case D3DDECLTYPE_FLOAT16_4
:
6518 return weld_float16_4(to
, from
, epsilon
);
6520 case D3DDECLTYPE_UNUSED
:
6521 if (!fixme_once_unused
++)
6522 FIXME("D3DDECLTYPE_UNUSED welding not implemented.\n");
6526 if (!fixme_once_unknown
++)
6527 FIXME("Welding of unknown declaration type %d is not implemented.\n", type
);
6534 static FLOAT
get_component_epsilon(const D3DVERTEXELEMENT9
*decl_ptr
, const D3DXWELDEPSILONS
*epsilons
)
6536 FLOAT epsilon
= 0.0f
;
6537 /* Quiet FIXMEs as this is in a loop with potentially thousand of iterations. */
6538 static BOOL fixme_once_blendindices
= FALSE
;
6539 static BOOL fixme_once_positiont
= FALSE
;
6540 static BOOL fixme_once_fog
= FALSE
;
6541 static BOOL fixme_once_depth
= FALSE
;
6542 static BOOL fixme_once_sample
= FALSE
;
6543 static BOOL fixme_once_unknown
= FALSE
;
6545 switch (decl_ptr
->Usage
)
6547 case D3DDECLUSAGE_POSITION
:
6548 epsilon
= epsilons
->Position
;
6550 case D3DDECLUSAGE_BLENDWEIGHT
:
6551 epsilon
= epsilons
->BlendWeights
;
6553 case D3DDECLUSAGE_NORMAL
:
6554 epsilon
= epsilons
->Normals
;
6556 case D3DDECLUSAGE_PSIZE
:
6557 epsilon
= epsilons
->PSize
;
6559 case D3DDECLUSAGE_TEXCOORD
:
6561 BYTE usage_index
= decl_ptr
->UsageIndex
;
6562 if (usage_index
> 7)
6564 epsilon
= epsilons
->Texcoords
[usage_index
];
6567 case D3DDECLUSAGE_TANGENT
:
6568 epsilon
= epsilons
->Tangent
;
6570 case D3DDECLUSAGE_BINORMAL
:
6571 epsilon
= epsilons
->Binormal
;
6573 case D3DDECLUSAGE_TESSFACTOR
:
6574 epsilon
= epsilons
->TessFactor
;
6576 case D3DDECLUSAGE_COLOR
:
6577 if (decl_ptr
->UsageIndex
== 0)
6578 epsilon
= epsilons
->Diffuse
;
6579 else if (decl_ptr
->UsageIndex
== 1)
6580 epsilon
= epsilons
->Specular
;
6584 case D3DDECLUSAGE_BLENDINDICES
:
6585 if (!fixme_once_blendindices
++)
6586 FIXME("D3DDECLUSAGE_BLENDINDICES welding not implemented.\n");
6588 case D3DDECLUSAGE_POSITIONT
:
6589 if (!fixme_once_positiont
++)
6590 FIXME("D3DDECLUSAGE_POSITIONT welding not implemented.\n");
6592 case D3DDECLUSAGE_FOG
:
6593 if (!fixme_once_fog
++)
6594 FIXME("D3DDECLUSAGE_FOG welding not implemented.\n");
6596 case D3DDECLUSAGE_DEPTH
:
6597 if (!fixme_once_depth
++)
6598 FIXME("D3DDECLUSAGE_DEPTH welding not implemented.\n");
6600 case D3DDECLUSAGE_SAMPLE
:
6601 if (!fixme_once_sample
++)
6602 FIXME("D3DDECLUSAGE_SAMPLE welding not implemented.\n");
6605 if (!fixme_once_unknown
++)
6606 FIXME("Unknown usage %x\n", decl_ptr
->Usage
);
6613 /* Helper function for reading a 32-bit index buffer. */
6614 static inline DWORD
read_ib(void *index_buffer
, BOOL indices_are_32bit
,
6617 if (indices_are_32bit
)
6619 DWORD
*indices
= index_buffer
;
6620 return indices
[index
];
6624 WORD
*indices
= index_buffer
;
6625 return indices
[index
];
6629 /* Helper function for writing to a 32-bit index buffer. */
6630 static inline void write_ib(void *index_buffer
, BOOL indices_are_32bit
,
6631 DWORD index
, DWORD value
)
6633 if (indices_are_32bit
)
6635 DWORD
*indices
= index_buffer
;
6636 indices
[index
] = value
;
6640 WORD
*indices
= index_buffer
;
6641 indices
[index
] = value
;
6645 /*************************************************************************
6646 * D3DXWeldVertices (D3DX9_36.@)
6648 * Welds together similar vertices. The similarity between vert-
6649 * ices can be the position and other components such as
6653 * mesh [I] Mesh which vertices will be welded together.
6654 * flags [I] D3DXWELDEPSILONSFLAGS specifying how to weld.
6655 * epsilons [I] How similar a component needs to be for welding.
6656 * adjacency [I] Which faces are adjacent to other faces.
6657 * adjacency_out [O] Updated adjacency after welding.
6658 * face_remap_out [O] Which faces the old faces have been mapped to.
6659 * vertex_remap_out [O] Which vertices the old vertices have been mapped to.
6663 * Failure: D3DERR_INVALIDCALL, E_OUTOFMEMORY.
6666 * Attribute sorting not implemented.
6669 HRESULT WINAPI
D3DXWeldVertices(ID3DXMesh
*mesh
, DWORD flags
, const D3DXWELDEPSILONS
*epsilons
,
6670 const DWORD
*adjacency
, DWORD
*adjacency_out
, DWORD
*face_remap_out
, ID3DXBuffer
**vertex_remap_out
)
6672 DWORD
*adjacency_generated
= NULL
;
6673 const DWORD
*adjacency_ptr
;
6674 DWORD
*attributes
= NULL
;
6675 const FLOAT DEFAULT_EPSILON
= 1.0e-6f
;
6678 void *indices
= NULL
;
6679 BOOL indices_are_32bit
= mesh
->lpVtbl
->GetOptions(mesh
) & D3DXMESH_32BIT
;
6680 DWORD optimize_flags
;
6681 DWORD
*point_reps
= NULL
;
6682 ID3DXMeshImpl
*This
= impl_from_ID3DXMesh(mesh
);
6683 DWORD
*vertex_face_map
= NULL
;
6684 ID3DXBuffer
*vertex_remap
= NULL
;
6685 BYTE
*vertices
= NULL
;
6687 TRACE("(%p, %x, %p, %p, %p, %p, %p)\n", mesh
, flags
, epsilons
,
6688 adjacency
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6692 WARN("No flags is undefined. Using D3DXWELDEPSILONS_WELDPARTIALMATCHES instead.\n");
6693 flags
= D3DXWELDEPSILONS_WELDPARTIALMATCHES
;
6696 if (adjacency
) /* Use supplied adjacency. */
6698 adjacency_ptr
= adjacency
;
6700 else /* Adjacency has to be generated. */
6702 adjacency_generated
= HeapAlloc(GetProcessHeap(), 0, 3 * This
->numfaces
* sizeof(*adjacency_generated
));
6703 if (!adjacency_generated
)
6705 ERR("Couldn't allocate memory for adjacency_generated.\n");
6709 hr
= mesh
->lpVtbl
->GenerateAdjacency(mesh
, DEFAULT_EPSILON
, adjacency_generated
);
6712 ERR("Couldn't generate adjacency.\n");
6715 adjacency_ptr
= adjacency_generated
;
6718 /* Point representation says which vertices can be replaced. */
6719 point_reps
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*point_reps
));
6723 ERR("Couldn't allocate memory for point_reps.\n");
6726 hr
= mesh
->lpVtbl
->ConvertAdjacencyToPointReps(mesh
, adjacency_ptr
, point_reps
);
6729 ERR("ConvertAdjacencyToPointReps failed.\n");
6733 hr
= mesh
->lpVtbl
->LockIndexBuffer(mesh
, 0, &indices
);
6736 ERR("Couldn't lock index buffer.\n");
6740 hr
= mesh
->lpVtbl
->LockAttributeBuffer(mesh
, 0, &attributes
);
6743 ERR("Couldn't lock attribute buffer.\n");
6746 vertex_face_map
= HeapAlloc(GetProcessHeap(), 0, This
->numvertices
* sizeof(*vertex_face_map
));
6747 if (!vertex_face_map
)
6750 ERR("Couldn't allocate memory for vertex_face_map.\n");
6753 /* Build vertex face map, so that a vertex's face can be looked up. */
6754 for (i
= 0; i
< This
->numfaces
; i
++)
6757 for (j
= 0; j
< 3; j
++)
6759 DWORD index
= read_ib(indices
, indices_are_32bit
, 3*i
+ j
);
6760 vertex_face_map
[index
] = i
;
6764 if (flags
& D3DXWELDEPSILONS_WELDPARTIALMATCHES
)
6766 hr
= mesh
->lpVtbl
->LockVertexBuffer(mesh
, 0, (void**)&vertices
);
6769 ERR("Couldn't lock vertex buffer.\n");
6772 /* For each vertex that can be removed, compare its vertex components
6773 * with the vertex components from the vertex that can replace it. A
6774 * vertex is only fully replaced if all the components match and the
6775 * flag D3DXWELDEPSILONS_DONOTREMOVEVERTICES is not set, and they
6776 * belong to the same attribute group. Otherwise the vertex components
6777 * that are within epsilon are set to the same value.
6779 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6781 D3DVERTEXELEMENT9
*decl_ptr
;
6782 DWORD vertex_size
= mesh
->lpVtbl
->GetNumBytesPerVertex(mesh
);
6783 DWORD num_vertex_components
;
6786 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6788 for (decl_ptr
= This
->cached_declaration
, num_vertex_components
= 0; decl_ptr
->Stream
!= 0xFF; decl_ptr
++, num_vertex_components
++)
6790 BYTE
*to
= &vertices
[vertex_size
*index
+ decl_ptr
->Offset
];
6791 BYTE
*from
= &vertices
[vertex_size
*point_reps
[index
] + decl_ptr
->Offset
];
6792 FLOAT epsilon
= get_component_epsilon(decl_ptr
, epsilons
);
6794 /* Don't weld self */
6795 if (index
== point_reps
[index
])
6801 if (weld_component(to
, from
, decl_ptr
->Type
, epsilon
))
6805 all_match
= (num_vertex_components
== matches
);
6806 if (all_match
&& !(flags
& D3DXWELDEPSILONS_DONOTREMOVEVERTICES
))
6808 DWORD to_face
= vertex_face_map
[index
];
6809 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6810 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6812 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6815 mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6818 else if (flags
& D3DXWELDEPSILONS_WELDALL
)
6820 for (i
= 0; i
< 3 * This
->numfaces
; i
++)
6822 DWORD index
= read_ib(indices
, indices_are_32bit
, i
);
6823 DWORD to_face
= vertex_face_map
[index
];
6824 DWORD from_face
= vertex_face_map
[point_reps
[index
]];
6825 if(attributes
[to_face
] != attributes
[from_face
] && !(flags
& D3DXWELDEPSILONS_DONOTSPLIT
))
6827 write_ib(indices
, indices_are_32bit
, i
, point_reps
[index
]);
6830 mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6832 mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6835 /* Compact mesh using OptimizeInplace */
6836 optimize_flags
= D3DXMESHOPT_COMPACT
;
6837 hr
= mesh
->lpVtbl
->OptimizeInplace(mesh
, optimize_flags
, adjacency_ptr
, adjacency_out
, face_remap_out
, vertex_remap_out
);
6840 ERR("Couldn't compact mesh.\n");
6846 HeapFree(GetProcessHeap(), 0, adjacency_generated
);
6847 HeapFree(GetProcessHeap(), 0, point_reps
);
6848 HeapFree(GetProcessHeap(), 0, vertex_face_map
);
6849 if (attributes
) mesh
->lpVtbl
->UnlockAttributeBuffer(mesh
);
6850 if (indices
) mesh
->lpVtbl
->UnlockIndexBuffer(mesh
);
6851 if (vertex_remap
) ID3DXBuffer_Release(vertex_remap
);
6852 if (vertices
) mesh
->lpVtbl
->UnlockVertexBuffer(mesh
);
6857 /*************************************************************************
6858 * D3DXOptimizeFaces (D3DX9_36.@)
6860 * Re-orders the faces so the vertex cache is used optimally.
6863 * indices [I] Pointer to an index buffer belonging to a mesh.
6864 * num_faces [I] Number of faces in the mesh.
6865 * num_vertices [I] Number of vertices in the mesh.
6866 * indices_are_32bit [I] Specifies whether indices are 32- or 16-bit.
6867 * face_remap [I/O] The new order the faces should be drawn in.
6871 * Failure: D3DERR_INVALIDCALL.
6874 * The face re-ordering does not use the vertex cache optimally.
6877 HRESULT WINAPI
D3DXOptimizeFaces(LPCVOID indices
,
6880 BOOL indices_are_32bit
,
6884 UINT j
= num_faces
- 1;
6885 UINT limit_16_bit
= 2 << 15; /* According to MSDN */
6886 HRESULT hr
= D3D_OK
;
6888 FIXME("(%p, %u, %u, %s, %p): semi-stub. Face order will not be optimal.\n",
6889 indices
, num_faces
, num_vertices
,
6890 indices_are_32bit
? "TRUE" : "FALSE", face_remap
);
6892 if (!indices_are_32bit
&& num_faces
>= limit_16_bit
)
6894 WARN("Number of faces must be less than %d when using 16-bit indices.\n",
6896 hr
= D3DERR_INVALIDCALL
;
6902 WARN("Face remap pointer is NULL.\n");
6903 hr
= D3DERR_INVALIDCALL
;
6907 /* The faces are drawn in reverse order for simple meshes. This ordering
6908 * is not optimal for complicated meshes, but will not break anything
6909 * either. The ordering should be changed to take advantage of the vertex
6910 * cache on the graphics card.
6912 * TODO Re-order to take advantage of vertex cache.
6914 for (i
= 0; i
< num_faces
; i
++)
6916 face_remap
[i
] = j
--;