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
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
28 #define NONAMELESSUNION
32 #include "wine/debug.h"
33 #include "wine/unicode.h"
34 #include "d3dx9_36_private.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
38 typedef struct ID3DXMeshImpl
40 ID3DXMesh ID3DXMesh_iface;
47 IDirect3DDevice9 *device;
48 IDirect3DVertexDeclaration9 *vertex_declaration;
49 IDirect3DVertexBuffer9 *vertex_buffer;
50 IDirect3DIndexBuffer9 *index_buffer;
53 static inline ID3DXMeshImpl *impl_from_ID3DXMesh(ID3DXMesh *iface)
55 return CONTAINING_RECORD(iface, ID3DXMeshImpl, ID3DXMesh_iface);
58 static HRESULT WINAPI ID3DXMeshImpl_QueryInterface(ID3DXMesh *iface, REFIID riid, LPVOID *object)
60 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
62 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), object);
64 if (IsEqualGUID(riid, &IID_IUnknown) ||
65 IsEqualGUID(riid, &IID_ID3DXBaseMesh) ||
66 IsEqualGUID(riid, &IID_ID3DXMesh))
68 iface->lpVtbl->AddRef(iface);
73 WARN("Interface %s not found.\n", debugstr_guid(riid));
78 static ULONG WINAPI ID3DXMeshImpl_AddRef(ID3DXMesh *iface)
80 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
82 TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
84 return InterlockedIncrement(&This->ref);
87 static ULONG WINAPI ID3DXMeshImpl_Release(ID3DXMesh *iface)
89 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
90 ULONG ref = InterlockedDecrement(&This->ref);
92 TRACE("(%p)->(): Release from %d\n", This, ref + 1);
96 IDirect3DIndexBuffer9_Release(This->index_buffer);
97 IDirect3DVertexBuffer9_Release(This->vertex_buffer);
98 IDirect3DVertexDeclaration9_Release(This->vertex_declaration);
99 IDirect3DDevice9_Release(This->device);
100 HeapFree(GetProcessHeap(), 0, This);
106 /*** ID3DXBaseMesh ***/
107 static HRESULT WINAPI ID3DXMeshImpl_DrawSubset(ID3DXMesh *iface, DWORD attrib_id)
109 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
111 FIXME("(%p)->(%u): stub\n", This, attrib_id);
116 static DWORD WINAPI ID3DXMeshImpl_GetNumFaces(ID3DXMesh *iface)
118 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
120 TRACE("(%p)\n", This);
122 return This->numfaces;
125 static DWORD WINAPI ID3DXMeshImpl_GetNumVertices(ID3DXMesh *iface)
127 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
129 TRACE("(%p)\n", This);
131 return This->numvertices;
134 static DWORD WINAPI ID3DXMeshImpl_GetFVF(ID3DXMesh *iface)
136 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
138 TRACE("(%p)\n", This);
143 static HRESULT WINAPI ID3DXMeshImpl_GetDeclaration(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
145 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
148 TRACE("(%p)\n", This);
150 if (declaration == NULL) return D3DERR_INVALIDCALL;
152 return IDirect3DVertexDeclaration9_GetDeclaration(This->vertex_declaration,
157 static DWORD WINAPI ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh *iface)
159 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
161 TRACE("iface (%p)\n", This);
163 return D3DXGetFVFVertexSize(This->fvf);
166 static DWORD WINAPI ID3DXMeshImpl_GetOptions(ID3DXMesh *iface)
168 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
170 TRACE("(%p)\n", This);
172 return This->options;
175 static HRESULT WINAPI ID3DXMeshImpl_GetDevice(ID3DXMesh *iface, LPDIRECT3DDEVICE9 *device)
177 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
179 TRACE("(%p)->(%p)\n", This, device);
181 if (device == NULL) return D3DERR_INVALIDCALL;
182 *device = This->device;
183 IDirect3DDevice9_AddRef(This->device);
188 static HRESULT WINAPI ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh *iface, DWORD options, DWORD fvf, LPDIRECT3DDEVICE9 device, LPD3DXMESH *clone_mesh)
190 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
192 FIXME("(%p)->(%u,%u,%p,%p): stub\n", This, options, fvf, device, clone_mesh);
197 static HRESULT WINAPI ID3DXMeshImpl_CloneMesh(ID3DXMesh *iface, DWORD options, CONST D3DVERTEXELEMENT9 *declaration, LPDIRECT3DDEVICE9 device,
198 LPD3DXMESH *clone_mesh)
200 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
202 FIXME("(%p)->(%u,%p,%p,%p): stub\n", This, options, declaration, device, clone_mesh);
207 static HRESULT WINAPI ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh *iface, LPDIRECT3DVERTEXBUFFER9 *vertex_buffer)
209 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
211 TRACE("(%p)->(%p)\n", This, vertex_buffer);
213 if (vertex_buffer == NULL) return D3DERR_INVALIDCALL;
214 *vertex_buffer = This->vertex_buffer;
215 IDirect3DVertexBuffer9_AddRef(This->vertex_buffer);
220 static HRESULT WINAPI ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh *iface, LPDIRECT3DINDEXBUFFER9 *index_buffer)
222 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
224 TRACE("(%p)->(%p)\n", This, index_buffer);
226 if (index_buffer == NULL) return D3DERR_INVALIDCALL;
227 *index_buffer = This->index_buffer;
228 IDirect3DIndexBuffer9_AddRef(This->index_buffer);
233 static HRESULT WINAPI ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
235 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
237 TRACE("(%p)->(%u,%p)\n", This, flags, data);
239 return IDirect3DVertexBuffer9_Lock(This->vertex_buffer, 0, 0, data, flags);
242 static HRESULT WINAPI ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh *iface)
244 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
246 TRACE("(%p)\n", This);
248 return IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
251 static HRESULT WINAPI ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
253 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
255 TRACE("(%p)->(%u,%p)\n", This, flags, data);
257 return IDirect3DIndexBuffer9_Lock(This->index_buffer, 0, 0, data, flags);
260 static HRESULT WINAPI ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh *iface)
262 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
264 TRACE("(%p)\n", This);
266 return IDirect3DIndexBuffer9_Unlock(This->index_buffer);
269 static HRESULT WINAPI ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTRIBUTERANGE *attrib_table, DWORD *attrib_table_size)
271 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
273 FIXME("(%p)->(%p,%p): stub\n", This, attrib_table, attrib_table_size);
278 static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency)
280 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
282 FIXME("(%p)->(%p,%p): stub\n", This, point_reps, adjacency);
287 static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, CONST DWORD *adjacency, DWORD *point_reps)
289 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
291 FIXME("(%p)->(%p,%p): stub\n", This, adjacency, point_reps);
296 static HRESULT WINAPI ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh *iface, FLOAT epsilon, DWORD *adjacency)
298 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
300 FIXME("(%p)->(%f,%p): stub\n", This, epsilon, adjacency);
305 static HRESULT WINAPI ID3DXMeshImpl_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
307 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
309 FIXME("(%p)->(%p): stub\n", This, declaration);
315 static HRESULT WINAPI ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh *iface, DWORD flags, DWORD **data)
317 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
319 FIXME("(%p)->(%u,%p): stub\n", This, flags, data);
324 static HRESULT WINAPI ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh *iface)
326 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
328 FIXME("(%p): stub\n", This);
333 static HRESULT WINAPI ID3DXMeshImpl_Optimize(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
334 DWORD *face_remap, LPD3DXBUFFER *vertex_remap, LPD3DXMESH *opt_mesh)
336 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
338 FIXME("(%p)->(%u,%p,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap, opt_mesh);
343 static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
344 DWORD *face_remap, LPD3DXBUFFER *vertex_remap)
346 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
348 FIXME("(%p)->(%u,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap);
353 static HRESULT WINAPI ID3DXMeshImpl_SetAttributeTable(ID3DXMesh *iface, CONST D3DXATTRIBUTERANGE *attrib_table, DWORD attrib_table_size)
355 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
357 FIXME("(%p)->(%p,%u): stub\n", This, attrib_table, attrib_table_size);
362 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl =
364 /*** IUnknown methods ***/
365 ID3DXMeshImpl_QueryInterface,
366 ID3DXMeshImpl_AddRef,
367 ID3DXMeshImpl_Release,
368 /*** ID3DXBaseMesh ***/
369 ID3DXMeshImpl_DrawSubset,
370 ID3DXMeshImpl_GetNumFaces,
371 ID3DXMeshImpl_GetNumVertices,
372 ID3DXMeshImpl_GetFVF,
373 ID3DXMeshImpl_GetDeclaration,
374 ID3DXMeshImpl_GetNumBytesPerVertex,
375 ID3DXMeshImpl_GetOptions,
376 ID3DXMeshImpl_GetDevice,
377 ID3DXMeshImpl_CloneMeshFVF,
378 ID3DXMeshImpl_CloneMesh,
379 ID3DXMeshImpl_GetVertexBuffer,
380 ID3DXMeshImpl_GetIndexBuffer,
381 ID3DXMeshImpl_LockVertexBuffer,
382 ID3DXMeshImpl_UnlockVertexBuffer,
383 ID3DXMeshImpl_LockIndexBuffer,
384 ID3DXMeshImpl_UnlockIndexBuffer,
385 ID3DXMeshImpl_GetAttributeTable,
386 ID3DXMeshImpl_ConvertPointRepsToAdjacency,
387 ID3DXMeshImpl_ConvertAdjacencyToPointReps,
388 ID3DXMeshImpl_GenerateAdjacency,
389 ID3DXMeshImpl_UpdateSemantics,
391 ID3DXMeshImpl_LockAttributeBuffer,
392 ID3DXMeshImpl_UnlockAttributeBuffer,
393 ID3DXMeshImpl_Optimize,
394 ID3DXMeshImpl_OptimizeInplace,
395 ID3DXMeshImpl_SetAttributeTable
398 /*************************************************************************
401 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
403 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
404 Amy Williams University of Utah
405 Steve Barrus University of Utah
406 R. Keith Morley University of Utah
407 Peter Shirley University of Utah
409 International Conference on Computer Graphics and Interactive Techniques archive
410 ACM SIGGRAPH 2005 Courses
411 Los Angeles, California
413 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
415 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
416 against each slab, if there's anything left of the ray after we're
417 done we've got an intersection of the ray with the box.
421 FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
423 div = 1.0f / praydirection->x;
426 tmin = ( pmin->x - prayposition->x ) * div;
427 tmax = ( pmax->x - prayposition->x ) * div;
431 tmin = ( pmax->x - prayposition->x ) * div;
432 tmax = ( pmin->x - prayposition->x ) * div;
435 if ( tmax < 0.0f ) return FALSE;
437 div = 1.0f / praydirection->y;
440 tymin = ( pmin->y - prayposition->y ) * div;
441 tymax = ( pmax->y - prayposition->y ) * div;
445 tymin = ( pmax->y - prayposition->y ) * div;
446 tymax = ( pmin->y - prayposition->y ) * div;
449 if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
451 if ( tymin > tmin ) tmin = tymin;
452 if ( tymax < tmax ) tmax = tymax;
454 div = 1.0f / praydirection->z;
457 tzmin = ( pmin->z - prayposition->z ) * div;
458 tzmax = ( pmax->z - prayposition->z ) * div;
462 tzmin = ( pmax->z - prayposition->z ) * div;
463 tzmax = ( pmin->z - prayposition->z ) * div;
466 if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
471 /*************************************************************************
472 * D3DXComputeBoundingBox
474 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
479 if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
481 *pmin = *pfirstposition;
484 for(i=0; i<numvertices; i++)
486 vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
488 if ( vec.x < pmin->x ) pmin->x = vec.x;
489 if ( vec.x > pmax->x ) pmax->x = vec.x;
491 if ( vec.y < pmin->y ) pmin->y = vec.y;
492 if ( vec.y > pmax->y ) pmax->y = vec.y;
494 if ( vec.z < pmin->z ) pmin->z = vec.z;
495 if ( vec.z > pmax->z ) pmax->z = vec.z;
501 /*************************************************************************
502 * D3DXComputeBoundingSphere
504 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
506 D3DXVECTOR3 temp, temp1;
510 if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
518 for(i=0; i<numvertices; i++)
520 D3DXVec3Add(&temp1, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
524 D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
526 for(i=0; i<numvertices; i++)
528 d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
529 if ( d > *pradius ) *pradius = d;
534 static const UINT d3dx_decltype_size[D3DDECLTYPE_UNUSED] =
536 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
537 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
538 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
539 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
540 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
541 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
542 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
543 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
544 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
545 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
546 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
547 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
548 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
549 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
550 /* D3DDECLTYPE_DEC3N */ 4,
551 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
552 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
555 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
556 D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
558 declaration[*idx].Stream = 0;
559 declaration[*idx].Offset = *offset;
560 declaration[*idx].Type = type;
561 declaration[*idx].Method = D3DDECLMETHOD_DEFAULT;
562 declaration[*idx].Usage = usage;
563 declaration[*idx].UsageIndex = usage_idx;
565 *offset += d3dx_decltype_size[type];
569 /*************************************************************************
570 * D3DXDeclaratorFromFVF
572 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
574 static const D3DVERTEXELEMENT9 end_element = D3DDECL_END();
575 DWORD tex_count = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
576 unsigned int offset = 0;
577 unsigned int idx = 0;
580 TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
582 if (fvf & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) return D3DERR_INVALIDCALL;
584 if (fvf & D3DFVF_POSITION_MASK)
586 BOOL has_blend = (fvf & D3DFVF_XYZB5) >= D3DFVF_XYZB1;
587 DWORD blend_count = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
588 BOOL has_blend_idx = (fvf & D3DFVF_LASTBETA_D3DCOLOR) || (fvf & D3DFVF_LASTBETA_UBYTE4);
590 if (has_blend_idx) --blend_count;
592 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
593 || (has_blend && blend_count > 4))
594 return D3DERR_INVALIDCALL;
596 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
597 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_POSITIONT, 0);
599 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_POSITION, 0);
608 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_BLENDWEIGHT, 0);
611 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_BLENDWEIGHT, 0);
614 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_BLENDWEIGHT, 0);
617 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_BLENDWEIGHT, 0);
620 ERR("Invalid blend count %u.\n", blend_count);
626 if (fvf & D3DFVF_LASTBETA_UBYTE4)
627 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_UBYTE4, D3DDECLUSAGE_BLENDINDICES, 0);
628 else if (fvf & D3DFVF_LASTBETA_D3DCOLOR)
629 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_BLENDINDICES, 0);
634 if (fvf & D3DFVF_NORMAL)
635 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_NORMAL, 0);
636 if (fvf & D3DFVF_PSIZE)
637 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_PSIZE, 0);
638 if (fvf & D3DFVF_DIFFUSE)
639 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 0);
640 if (fvf & D3DFVF_SPECULAR)
641 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 1);
643 for (i = 0; i < tex_count; ++i)
645 switch ((fvf >> (16 + 2 * i)) & 0x03)
647 case D3DFVF_TEXTUREFORMAT1:
648 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_TEXCOORD, i);
650 case D3DFVF_TEXTUREFORMAT2:
651 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_TEXCOORD, i);
653 case D3DFVF_TEXTUREFORMAT3:
654 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_TEXCOORD, i);
656 case D3DFVF_TEXTUREFORMAT4:
657 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_TEXCOORD, i);
662 declaration[idx] = end_element;
667 /*************************************************************************
668 * D3DXFVFFromDeclarator
670 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
672 unsigned int i = 0, texture, offset;
674 TRACE("(%p, %p)\n", declaration, fvf);
677 if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
679 if ((declaration[1].Type == D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
680 declaration[1].UsageIndex == 0) &&
681 (declaration[2].Type == D3DDECLTYPE_FLOAT1 && declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES &&
682 declaration[2].UsageIndex == 0))
684 return D3DERR_INVALIDCALL;
686 else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
687 declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
689 if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
691 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
695 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
699 else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
700 declaration[1].UsageIndex == 0)
702 if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
703 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
705 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
707 *fvf |= D3DFVF_LASTBETA_UBYTE4;
711 *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
713 switch (declaration[1].Type)
715 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB2; break;
716 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB3; break;
717 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB4; break;
718 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB5; break;
724 switch (declaration[1].Type)
726 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB1; break;
727 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB2; break;
728 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB3; break;
729 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB4; break;
740 else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
741 declaration[0].UsageIndex == 0)
743 *fvf |= D3DFVF_XYZRHW;
747 if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
749 *fvf |= D3DFVF_NORMAL;
752 if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
753 declaration[i].UsageIndex == 0)
755 *fvf |= D3DFVF_PSIZE;
758 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
759 declaration[i].UsageIndex == 0)
761 *fvf |= D3DFVF_DIFFUSE;
764 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
765 declaration[i].UsageIndex == 1)
767 *fvf |= D3DFVF_SPECULAR;
771 for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
773 if (declaration[i].Stream == 0xFF)
777 else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
778 declaration[i].UsageIndex == texture)
780 *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
782 else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
783 declaration[i].UsageIndex == texture)
785 *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
787 else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
788 declaration[i].UsageIndex == texture)
790 *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
792 else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
793 declaration[i].UsageIndex == texture)
795 *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
799 return D3DERR_INVALIDCALL;
803 *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
805 for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
806 offset += d3dx_decltype_size[declaration[i].Type], i++)
808 if (declaration[i].Offset != offset)
810 return D3DERR_INVALIDCALL;
817 /*************************************************************************
818 * D3DXGetFVFVertexSize
820 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
822 return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
825 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
829 UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
831 if (FVF & D3DFVF_NORMAL) size += sizeof(D3DXVECTOR3);
832 if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
833 if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
834 if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
836 switch (FVF & D3DFVF_POSITION_MASK)
838 case D3DFVF_XYZ: size += sizeof(D3DXVECTOR3); break;
839 case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
840 case D3DFVF_XYZB1: size += 4 * sizeof(FLOAT); break;
841 case D3DFVF_XYZB2: size += 5 * sizeof(FLOAT); break;
842 case D3DFVF_XYZB3: size += 6 * sizeof(FLOAT); break;
843 case D3DFVF_XYZB4: size += 7 * sizeof(FLOAT); break;
844 case D3DFVF_XYZB5: size += 8 * sizeof(FLOAT); break;
845 case D3DFVF_XYZW: size += 4 * sizeof(FLOAT); break;
848 for (i = 0; i < numTextures; i++)
850 size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
856 /*************************************************************************
857 * D3DXGetDeclVertexSize
859 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
861 const D3DVERTEXELEMENT9 *element;
864 TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
868 for (element = decl; element->Stream != 0xff; ++element)
872 if (element->Stream != stream_idx) continue;
874 if (element->Type >= sizeof(d3dx_decltype_size) / sizeof(*d3dx_decltype_size))
876 FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
880 type_size = d3dx_decltype_size[element->Type];
881 if (element->Offset + type_size > size) size = element->Offset + type_size;
887 /*************************************************************************
890 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
892 const D3DVERTEXELEMENT9 *element;
894 TRACE("decl %p\n", decl);
896 /* null decl results in exception on Windows XP */
898 for (element = decl; element->Stream != 0xff; ++element);
900 return element - decl;
903 /*************************************************************************
906 BOOL WINAPI D3DXIntersectTri(CONST D3DXVECTOR3 *p0, CONST D3DXVECTOR3 *p1, CONST D3DXVECTOR3 *p2, CONST D3DXVECTOR3 *praypos, CONST D3DXVECTOR3 *praydir, FLOAT *pu, FLOAT *pv, FLOAT *pdist)
911 m.u.m[0][0] = p1->x - p0->x;
912 m.u.m[1][0] = p2->x - p0->x;
913 m.u.m[2][0] = -praydir->x;
915 m.u.m[0][1] = p1->y - p0->z;
916 m.u.m[1][1] = p2->y - p0->z;
917 m.u.m[2][1] = -praydir->y;
919 m.u.m[0][2] = p1->z - p0->z;
920 m.u.m[1][2] = p2->z - p0->z;
921 m.u.m[2][2] = -praydir->z;
928 vec.x = praypos->x - p0->x;
929 vec.y = praypos->y - p0->y;
930 vec.z = praypos->z - p0->z;
933 if ( D3DXMatrixInverse(&m, NULL, &m) )
935 D3DXVec4Transform(&vec, &vec, &m);
936 if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
940 *pdist = fabs( vec.z );
948 /*************************************************************************
949 * D3DXSphereBoundProbe
951 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
953 D3DXVECTOR3 difference;
956 a = D3DXVec3LengthSq(praydirection);
957 if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
958 b = D3DXVec3Dot(&difference, praydirection);
959 c = D3DXVec3LengthSq(&difference) - radius * radius;
962 if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
966 /*************************************************************************
969 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options, CONST D3DVERTEXELEMENT9 *declaration,
970 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
974 IDirect3DVertexDeclaration9 *vertex_declaration;
975 IDirect3DVertexBuffer9 *vertex_buffer;
976 IDirect3DIndexBuffer9 *index_buffer;
977 ID3DXMeshImpl *object;
979 TRACE("(%d, %d, %d, %p, %p, %p)\n", numfaces, numvertices, options, declaration, device, mesh);
981 if (numfaces == 0 || numvertices == 0 || declaration == NULL || device == NULL || mesh == NULL)
983 return D3DERR_INVALIDCALL;
986 hr = D3DXFVFFromDeclarator(declaration, &fvf);
992 /* Create vertex declaration */
993 hr = IDirect3DDevice9_CreateVertexDeclaration(device,
995 &vertex_declaration);
998 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
1002 /* Create vertex buffer */
1003 hr = IDirect3DDevice9_CreateVertexBuffer(device,
1004 numvertices * D3DXGetDeclVertexSize(declaration, declaration[0].Stream),
1012 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1013 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1017 /* Create index buffer */
1018 hr = IDirect3DDevice9_CreateIndexBuffer(device,
1019 numfaces * 6, /* 3 vertices per triangle, 2 triangles per face */
1027 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1028 IDirect3DVertexBuffer9_Release(vertex_buffer);
1029 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1033 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXMeshImpl));
1036 IDirect3DIndexBuffer9_Release(index_buffer);
1037 IDirect3DVertexBuffer9_Release(vertex_buffer);
1038 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1040 return E_OUTOFMEMORY;
1042 object->ID3DXMesh_iface.lpVtbl = &D3DXMesh_Vtbl;
1045 object->numfaces = numfaces;
1046 object->numvertices = numvertices;
1047 object->options = options;
1049 object->device = device;
1050 IDirect3DDevice9_AddRef(device);
1052 object->vertex_declaration = vertex_declaration;
1053 object->vertex_buffer = vertex_buffer;
1054 object->index_buffer = index_buffer;
1056 *mesh = &object->ID3DXMesh_iface;
1061 /*************************************************************************
1064 HRESULT WINAPI D3DXCreateMeshFVF(DWORD numfaces, DWORD numvertices, DWORD options, DWORD fvf,
1065 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
1068 D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
1070 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces, numvertices, options, fvf, device, mesh);
1072 hr = D3DXDeclaratorFromFVF(fvf, declaration);
1073 if (FAILED(hr)) return hr;
1075 return D3DXCreateMesh(numfaces, numvertices, options, declaration, device, mesh);
1078 HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height,
1079 FLOAT depth, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1081 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device, width, height, depth, mesh, adjacency);
1088 D3DXVECTOR3 position;
1092 typedef WORD face[3];
1100 static void free_sincos_table(struct sincos_table *sincos_table)
1102 HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1103 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1106 /* pre compute sine and cosine tables; caller must free */
1107 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1112 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1113 if (!sincos_table->sin)
1117 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1118 if (!sincos_table->cos)
1120 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1124 angle = angle_start;
1125 for (i = 0; i < n; i++)
1127 sincos_table->sin[i] = sin(angle);
1128 sincos_table->cos[i] = cos(angle);
1129 angle += angle_step;
1135 static WORD vertex_index(UINT slices, int slice, int stack)
1137 return stack*slices+slice+1;
1140 HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices,
1141 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1143 DWORD number_of_vertices, number_of_faces;
1146 struct vertex *vertices;
1148 float phi_step, phi_start;
1149 struct sincos_table phi;
1150 float theta_step, theta, sin_theta, cos_theta;
1154 TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency);
1156 if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh)
1158 return D3DERR_INVALIDCALL;
1163 FIXME("Case of adjacency != NULL not implemented.\n");
1167 number_of_vertices = 2 + slices * (stacks-1);
1168 number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1170 hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1171 D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere);
1177 hr = sphere->lpVtbl->LockVertexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1180 sphere->lpVtbl->Release(sphere);
1184 hr = sphere->lpVtbl->LockIndexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&faces);
1187 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1188 sphere->lpVtbl->Release(sphere);
1192 /* phi = angle on xz plane wrt z axis */
1193 phi_step = -2 * M_PI / slices;
1194 phi_start = M_PI / 2;
1196 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1198 sphere->lpVtbl->UnlockIndexBuffer(sphere);
1199 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1200 sphere->lpVtbl->Release(sphere);
1201 return E_OUTOFMEMORY;
1204 /* theta = angle on xy plane wrt x axis */
1205 theta_step = M_PI / stacks;
1212 vertices[vertex].normal.x = 0.0f;
1213 vertices[vertex].normal.y = 0.0f;
1214 vertices[vertex].normal.z = 1.0f;
1215 vertices[vertex].position.x = 0.0f;
1216 vertices[vertex].position.y = 0.0f;
1217 vertices[vertex].position.z = radius;
1220 for (stack = 0; stack < stacks - 1; stack++)
1222 sin_theta = sin(theta);
1223 cos_theta = cos(theta);
1225 for (slice = 0; slice < slices; slice++)
1227 vertices[vertex].normal.x = sin_theta * phi.cos[slice];
1228 vertices[vertex].normal.y = sin_theta * phi.sin[slice];
1229 vertices[vertex].normal.z = cos_theta;
1230 vertices[vertex].position.x = radius * sin_theta * phi.cos[slice];
1231 vertices[vertex].position.y = radius * sin_theta * phi.sin[slice];
1232 vertices[vertex].position.z = radius * cos_theta;
1239 /* top stack is triangle fan */
1241 faces[face][1] = slice + 1;
1242 faces[face][2] = slice;
1247 /* stacks in between top and bottom are quad strips */
1248 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1249 faces[face][1] = vertex_index(slices, slice, stack-1);
1250 faces[face][2] = vertex_index(slices, slice-1, stack);
1253 faces[face][0] = vertex_index(slices, slice, stack-1);
1254 faces[face][1] = vertex_index(slices, slice, stack);
1255 faces[face][2] = vertex_index(slices, slice-1, stack);
1261 theta += theta_step;
1267 faces[face][2] = slice;
1272 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1273 faces[face][1] = vertex_index(slices, 0, stack-1);
1274 faces[face][2] = vertex_index(slices, slice-1, stack);
1277 faces[face][0] = vertex_index(slices, 0, stack-1);
1278 faces[face][1] = vertex_index(slices, 0, stack);
1279 faces[face][2] = vertex_index(slices, slice-1, stack);
1284 vertices[vertex].position.x = 0.0f;
1285 vertices[vertex].position.y = 0.0f;
1286 vertices[vertex].position.z = -radius;
1287 vertices[vertex].normal.x = 0.0f;
1288 vertices[vertex].normal.y = 0.0f;
1289 vertices[vertex].normal.z = -1.0f;
1291 /* bottom stack is triangle fan */
1292 for (slice = 1; slice < slices; slice++)
1294 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1295 faces[face][1] = vertex_index(slices, slice, stack-1);
1296 faces[face][2] = vertex;
1300 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1301 faces[face][1] = vertex_index(slices, 0, stack-1);
1302 faces[face][2] = vertex;
1304 free_sincos_table(&phi);
1305 sphere->lpVtbl->UnlockIndexBuffer(sphere);
1306 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1312 HRESULT WINAPI D3DXCreateCylinder(LPDIRECT3DDEVICE9 device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices,
1313 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1315 DWORD number_of_vertices, number_of_faces;
1317 ID3DXMesh *cylinder;
1318 struct vertex *vertices;
1320 float theta_step, theta_start;
1321 struct sincos_table theta;
1322 float delta_radius, radius, radius_step;
1323 float z, z_step, z_normal;
1327 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device, radius1, radius2, length, slices, stacks, mesh, adjacency);
1329 if (device == NULL || radius1 < 0.0f || radius2 < 0.0f || length < 0.0f || slices < 2 || stacks < 1 || mesh == NULL)
1331 return D3DERR_INVALIDCALL;
1336 FIXME("Case of adjacency != NULL not implemented.\n");
1340 number_of_vertices = 2 + (slices * (3 + stacks));
1341 number_of_faces = 2 * slices + stacks * (2 * slices);
1343 hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1344 D3DFVF_XYZ | D3DFVF_NORMAL, device, &cylinder);
1350 hr = cylinder->lpVtbl->LockVertexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1353 cylinder->lpVtbl->Release(cylinder);
1357 hr = cylinder->lpVtbl->LockIndexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&faces);
1360 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1361 cylinder->lpVtbl->Release(cylinder);
1365 /* theta = angle on xy plane wrt x axis */
1366 theta_step = -2 * M_PI / slices;
1367 theta_start = M_PI / 2;
1369 if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1371 cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1372 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1373 cylinder->lpVtbl->Release(cylinder);
1374 return E_OUTOFMEMORY;
1380 delta_radius = radius1 - radius2;
1382 radius_step = delta_radius / stacks;
1385 z_step = length / stacks;
1386 z_normal = delta_radius / length;
1387 if (isnan(z_normal))
1392 vertices[vertex].normal.x = 0.0f;
1393 vertices[vertex].normal.y = 0.0f;
1394 vertices[vertex].normal.z = -1.0f;
1395 vertices[vertex].position.x = 0.0f;
1396 vertices[vertex].position.y = 0.0f;
1397 vertices[vertex++].position.z = z;
1399 for (slice = 0; slice < slices; slice++, vertex++)
1401 vertices[vertex].normal.x = 0.0f;
1402 vertices[vertex].normal.y = 0.0f;
1403 vertices[vertex].normal.z = -1.0f;
1404 vertices[vertex].position.x = radius * theta.cos[slice];
1405 vertices[vertex].position.y = radius * theta.sin[slice];
1406 vertices[vertex].position.z = z;
1411 faces[face][1] = slice;
1412 faces[face++][2] = slice + 1;
1417 faces[face][1] = slice;
1418 faces[face++][2] = 1;
1420 for (stack = 1; stack <= stacks+1; stack++)
1422 for (slice = 0; slice < slices; slice++, vertex++)
1424 vertices[vertex].normal.x = theta.cos[slice];
1425 vertices[vertex].normal.y = theta.sin[slice];
1426 vertices[vertex].normal.z = z_normal;
1427 D3DXVec3Normalize(&vertices[vertex].normal, &vertices[vertex].normal);
1428 vertices[vertex].position.x = radius * theta.cos[slice];
1429 vertices[vertex].position.y = radius * theta.sin[slice];
1430 vertices[vertex].position.z = z;
1432 if (stack > 1 && slice > 0)
1434 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1435 faces[face][1] = vertex_index(slices, slice-1, stack);
1436 faces[face++][2] = vertex_index(slices, slice, stack-1);
1438 faces[face][0] = vertex_index(slices, slice, stack-1);
1439 faces[face][1] = vertex_index(slices, slice-1, stack);
1440 faces[face++][2] = vertex_index(slices, slice, stack);
1446 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1447 faces[face][1] = vertex_index(slices, slice-1, stack);
1448 faces[face++][2] = vertex_index(slices, 0, stack-1);
1450 faces[face][0] = vertex_index(slices, 0, stack-1);
1451 faces[face][1] = vertex_index(slices, slice-1, stack);
1452 faces[face++][2] = vertex_index(slices, 0, stack);
1455 if (stack < stacks + 1)
1458 radius -= radius_step;
1462 for (slice = 0; slice < slices; slice++, vertex++)
1464 vertices[vertex].normal.x = 0.0f;
1465 vertices[vertex].normal.y = 0.0f;
1466 vertices[vertex].normal.z = 1.0f;
1467 vertices[vertex].position.x = radius * theta.cos[slice];
1468 vertices[vertex].position.y = radius * theta.sin[slice];
1469 vertices[vertex].position.z = z;
1473 faces[face][0] = vertex_index(slices, slice-1, stack);
1474 faces[face][1] = number_of_vertices - 1;
1475 faces[face++][2] = vertex_index(slices, slice, stack);
1479 vertices[vertex].position.x = 0.0f;
1480 vertices[vertex].position.y = 0.0f;
1481 vertices[vertex].position.z = z;
1482 vertices[vertex].normal.x = 0.0f;
1483 vertices[vertex].normal.y = 0.0f;
1484 vertices[vertex].normal.z = 1.0f;
1486 faces[face][0] = vertex_index(slices, slice-1, stack);
1487 faces[face][1] = number_of_vertices - 1;
1488 faces[face][2] = vertex_index(slices, 0, stack);
1490 free_sincos_table(&theta);
1491 cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1492 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1498 HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER* adjacency)
1500 FIXME("(%p, %p, %p): stub\n", device, mesh, adjacency);
1505 HRESULT WINAPI D3DXCreateTextA(LPDIRECT3DDEVICE9 device,
1506 HDC hdc, LPCSTR text,
1507 FLOAT deviation, FLOAT extrusion,
1508 LPD3DXMESH *mesh, LPD3DXBUFFER *adjacency,
1509 LPGLYPHMETRICSFLOAT glyphmetrics)
1515 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device, hdc,
1516 debugstr_a(text), deviation, extrusion, mesh, adjacency, glyphmetrics);
1519 return D3DERR_INVALIDCALL;
1521 len = MultiByteToWideChar(CP_ACP, 0, text, -1, NULL, 0);
1522 textW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
1523 MultiByteToWideChar(CP_ACP, 0, text, -1, textW, len);
1525 hr = D3DXCreateTextW(device, hdc, textW, deviation, extrusion,
1526 mesh, adjacency, glyphmetrics);
1527 HeapFree(GetProcessHeap(), 0, textW);
1533 POINTTYPE_CURVE = 0,
1535 POINTTYPE_CURVE_START,
1536 POINTTYPE_CURVE_END,
1537 POINTTYPE_CURVE_MIDDLE,
1543 enum pointtype corner;
1546 struct dynamic_array
1548 int count, capacity;
1552 /* is a dynamic_array */
1555 int count, capacity;
1556 struct point2d *items;
1559 /* is a dynamic_array */
1560 struct outline_array
1562 int count, capacity;
1563 struct outline *items;
1572 struct point2d_index
1574 struct outline *outline;
1578 struct point2d_index_array
1581 struct point2d_index *items;
1586 struct outline_array outlines;
1587 struct face_array faces;
1588 struct point2d_index_array ordered_vertices;
1592 /* is an dynamic_array */
1595 int count, capacity;
1599 /* complex polygons are split into monotone polygons, which have
1600 * at most 2 intersections with the vertical sweep line */
1601 struct triangulation
1603 struct word_array vertex_stack;
1604 BOOL last_on_top, merging;
1607 /* is an dynamic_array */
1608 struct triangulation_array
1610 int count, capacity;
1611 struct triangulation *items;
1613 struct glyphinfo *glyph;
1616 static BOOL reserve(struct dynamic_array *array, int count, int itemsize)
1618 if (count > array->capacity) {
1621 if (array->items && array->capacity) {
1622 new_capacity = max(array->capacity * 2, count);
1623 new_buffer = HeapReAlloc(GetProcessHeap(), 0, array->items, new_capacity * itemsize);
1625 new_capacity = max(16, count);
1626 new_buffer = HeapAlloc(GetProcessHeap(), 0, new_capacity * itemsize);
1630 array->items = new_buffer;
1631 array->capacity = new_capacity;
1636 static struct point2d *add_points(struct outline *array, int num)
1638 struct point2d *item;
1640 if (!reserve((struct dynamic_array *)array, array->count + num, sizeof(array->items[0])))
1643 item = &array->items[array->count];
1644 array->count += num;
1648 static struct outline *add_outline(struct outline_array *array)
1650 struct outline *item;
1652 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
1655 item = &array->items[array->count++];
1656 ZeroMemory(item, sizeof(*item));
1660 static inline face *add_face(struct face_array *array)
1662 return &array->items[array->count++];
1665 static struct triangulation *add_triangulation(struct triangulation_array *array)
1667 struct triangulation *item;
1669 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
1672 item = &array->items[array->count++];
1673 ZeroMemory(item, sizeof(*item));
1677 static HRESULT add_vertex_index(struct word_array *array, WORD vertex_index)
1679 if (!reserve((struct dynamic_array *)array, array->count + 1, sizeof(array->items[0])))
1680 return E_OUTOFMEMORY;
1682 array->items[array->count++] = vertex_index;
1686 /* assume fixed point numbers can be converted to float point in place */
1687 C_ASSERT(sizeof(FIXED) == sizeof(float));
1688 C_ASSERT(sizeof(POINTFX) == sizeof(D3DXVECTOR2));
1690 static inline D3DXVECTOR2 *convert_fixed_to_float(POINTFX *pt, int count, float emsquare)
1692 D3DXVECTOR2 *ret = (D3DXVECTOR2*)pt;
1694 D3DXVECTOR2 *pt_flt = (D3DXVECTOR2*)pt;
1695 pt_flt->x = (pt->x.value + pt->x.fract / (float)0x10000) / emsquare;
1696 pt_flt->y = (pt->y.value + pt->y.fract / (float)0x10000) / emsquare;
1702 static HRESULT add_bezier_points(struct outline *outline, const D3DXVECTOR2 *p1,
1703 const D3DXVECTOR2 *p2, const D3DXVECTOR2 *p3,
1704 float max_deviation_sq)
1706 D3DXVECTOR2 split1 = {0, 0}, split2 = {0, 0}, middle, vec;
1709 D3DXVec2Scale(&split1, D3DXVec2Add(&split1, p1, p2), 0.5f);
1710 D3DXVec2Scale(&split2, D3DXVec2Add(&split2, p2, p3), 0.5f);
1711 D3DXVec2Scale(&middle, D3DXVec2Add(&middle, &split1, &split2), 0.5f);
1713 deviation_sq = D3DXVec2LengthSq(D3DXVec2Subtract(&vec, &middle, p2));
1714 if (deviation_sq < max_deviation_sq) {
1715 struct point2d *pt = add_points(outline, 1);
1716 if (!pt) return E_OUTOFMEMORY;
1718 pt->corner = POINTTYPE_CURVE;
1719 /* the end point is omitted because the end line merges into the next segment of
1720 * the split bezier curve, and the end of the split bezier curve is added outside
1721 * this recursive function. */
1723 HRESULT hr = add_bezier_points(outline, p1, &split1, &middle, max_deviation_sq);
1724 if (hr != S_OK) return hr;
1725 hr = add_bezier_points(outline, &middle, &split2, p3, max_deviation_sq);
1726 if (hr != S_OK) return hr;
1732 static inline BOOL is_direction_similar(D3DXVECTOR2 *dir1, D3DXVECTOR2 *dir2, float cos_theta)
1734 /* dot product = cos(theta) */
1735 return D3DXVec2Dot(dir1, dir2) > cos_theta;
1738 static inline D3DXVECTOR2 *unit_vec2(D3DXVECTOR2 *dir, const D3DXVECTOR2 *pt1, const D3DXVECTOR2 *pt2)
1740 return D3DXVec2Normalize(D3DXVec2Subtract(dir, pt2, pt1), dir);
1750 static BOOL attempt_line_merge(struct outline *outline,
1752 const D3DXVECTOR2 *nextpt,
1754 const struct cos_table *table)
1756 D3DXVECTOR2 curdir, lastdir;
1757 struct point2d *prevpt, *pt;
1760 pt = &outline->items[pt_index];
1761 pt_index = (pt_index - 1 + outline->count) % outline->count;
1762 prevpt = &outline->items[pt_index];
1765 pt->corner = pt->corner != POINTTYPE_CORNER ? POINTTYPE_CURVE_MIDDLE : POINTTYPE_CURVE_START;
1767 if (outline->count < 2)
1770 /* remove last point if the next line continues the last line */
1771 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
1772 unit_vec2(&curdir, &pt->pos, nextpt);
1773 if (is_direction_similar(&lastdir, &curdir, table->cos_half))
1776 if (pt->corner == POINTTYPE_CURVE_END)
1777 prevpt->corner = pt->corner;
1778 if (prevpt->corner == POINTTYPE_CURVE_END && to_curve)
1779 prevpt->corner = POINTTYPE_CURVE_MIDDLE;
1783 if (outline->count < 2)
1786 pt_index = (pt_index - 1 + outline->count) % outline->count;
1787 prevpt = &outline->items[pt_index];
1788 unit_vec2(&lastdir, &prevpt->pos, &pt->pos);
1789 unit_vec2(&curdir, &pt->pos, nextpt);
1794 static HRESULT create_outline(struct glyphinfo *glyph, void *raw_outline, int datasize,
1795 float max_deviation_sq, float emsquare, const struct cos_table *cos_table)
1797 TTPOLYGONHEADER *header = (TTPOLYGONHEADER *)raw_outline;
1799 while ((char *)header < (char *)raw_outline + datasize)
1801 TTPOLYCURVE *curve = (TTPOLYCURVE *)(header + 1);
1802 struct point2d *lastpt, *pt;
1803 D3DXVECTOR2 lastdir;
1804 D3DXVECTOR2 *pt_flt;
1806 struct outline *outline = add_outline(&glyph->outlines);
1809 return E_OUTOFMEMORY;
1811 pt = add_points(outline, 1);
1813 return E_OUTOFMEMORY;
1814 pt_flt = convert_fixed_to_float(&header->pfxStart, 1, emsquare);
1816 pt->corner = POINTTYPE_CORNER;
1818 if (header->dwType != TT_POLYGON_TYPE)
1819 FIXME("Unknown header type %d\n", header->dwType);
1821 while ((char *)curve < (char *)header + header->cb)
1823 D3DXVECTOR2 bezier_start = outline->items[outline->count - 1].pos;
1824 BOOL to_curve = curve->wType != TT_PRIM_LINE && curve->cpfx > 1;
1827 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
1831 pt_flt = convert_fixed_to_float(curve->apfx, curve->cpfx, emsquare);
1833 attempt_line_merge(outline, outline->count - 1, &pt_flt[0], to_curve, cos_table);
1838 int count = curve->cpfx;
1843 D3DXVECTOR2 bezier_end;
1845 D3DXVec2Scale(&bezier_end, D3DXVec2Add(&bezier_end, &pt_flt[j], &pt_flt[j+1]), 0.5f);
1846 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &bezier_end, max_deviation_sq);
1849 bezier_start = bezier_end;
1853 hr = add_bezier_points(outline, &bezier_start, &pt_flt[j], &pt_flt[j+1], max_deviation_sq);
1857 pt = add_points(outline, 1);
1859 return E_OUTOFMEMORY;
1861 pt->pos = pt_flt[j];
1862 pt->corner = POINTTYPE_CURVE_END;
1864 pt = add_points(outline, curve->cpfx);
1866 return E_OUTOFMEMORY;
1867 for (j = 0; j < curve->cpfx; j++)
1869 pt->pos = pt_flt[j];
1870 pt->corner = POINTTYPE_CORNER;
1875 curve = (TTPOLYCURVE *)&curve->apfx[curve->cpfx];
1878 /* remove last point if the next line continues the last line */
1879 if (outline->count >= 3) {
1882 lastpt = &outline->items[outline->count - 1];
1883 pt = &outline->items[0];
1884 if (pt->pos.x == lastpt->pos.x && pt->pos.y == lastpt->pos.y) {
1885 if (lastpt->corner == POINTTYPE_CURVE_END)
1887 if (pt->corner == POINTTYPE_CURVE_START)
1888 pt->corner = POINTTYPE_CURVE_MIDDLE;
1890 pt->corner = POINTTYPE_CURVE_END;
1893 lastpt = &outline->items[outline->count - 1];
1895 /* outline closed with a line from end to start point */
1896 attempt_line_merge(outline, outline->count - 1, &pt->pos, FALSE, cos_table);
1898 lastpt = &outline->items[0];
1899 to_curve = lastpt->corner != POINTTYPE_CORNER && lastpt->corner != POINTTYPE_CURVE_END;
1900 if (lastpt->corner == POINTTYPE_CURVE_START)
1901 lastpt->corner = POINTTYPE_CORNER;
1902 pt = &outline->items[1];
1903 if (attempt_line_merge(outline, 0, &pt->pos, to_curve, cos_table))
1904 *lastpt = outline->items[outline->count];
1907 lastpt = &outline->items[outline->count - 1];
1908 pt = &outline->items[0];
1909 unit_vec2(&lastdir, &lastpt->pos, &pt->pos);
1910 for (j = 0; j < outline->count; j++)
1915 pt = &outline->items[(j + 1) % outline->count];
1916 unit_vec2(&curdir, &lastpt->pos, &pt->pos);
1918 switch (lastpt->corner)
1920 case POINTTYPE_CURVE_START:
1921 case POINTTYPE_CURVE_END:
1922 if (!is_direction_similar(&lastdir, &curdir, cos_table->cos_45))
1923 lastpt->corner = POINTTYPE_CORNER;
1925 case POINTTYPE_CURVE_MIDDLE:
1926 if (!is_direction_similar(&lastdir, &curdir, cos_table->cos_90))
1927 lastpt->corner = POINTTYPE_CORNER;
1929 lastpt->corner = POINTTYPE_CURVE;
1937 header = (TTPOLYGONHEADER *)((char *)header + header->cb);
1942 /* Get the y-distance from a line to a point */
1943 static float get_line_to_point_y_distance(D3DXVECTOR2 *line_pt1,
1944 D3DXVECTOR2 *line_pt2,
1947 D3DXVECTOR2 line_vec = {0, 0};
1951 D3DXVec2Subtract(&line_vec, line_pt2, line_pt1);
1952 line_pt_dx = point->x - line_pt1->x;
1953 line_y = line_pt1->y + (line_vec.y * line_pt_dx) / line_vec.x;
1954 return point->y - line_y;
1957 static D3DXVECTOR2 *get_indexed_point(struct point2d_index *pt_idx)
1959 return &pt_idx->outline->items[pt_idx->vertex].pos;
1962 static D3DXVECTOR2 *get_ordered_vertex(struct glyphinfo *glyph, WORD index)
1964 return get_indexed_point(&glyph->ordered_vertices.items[index]);
1967 static void remove_triangulation(struct triangulation_array *array, struct triangulation *item)
1969 HeapFree(GetProcessHeap(), 0, item->vertex_stack.items);
1970 MoveMemory(item, item + 1, (char*)&array->items[array->count] - (char*)(item + 1));
1974 static HRESULT triangulation_add_point(struct triangulation **t_ptr,
1975 struct triangulation_array *triangulations,
1979 struct glyphinfo *glyph = triangulations->glyph;
1980 struct triangulation *t = *t_ptr;
1985 if (t->last_on_top) {
1993 if (t->last_on_top != to_top && t->vertex_stack.count > 1) {
1994 /* consume all vertices on the stack */
1995 WORD last_pt = t->vertex_stack.items[0];
1997 for (i = 1; i < t->vertex_stack.count; i++)
1999 face = add_face(&glyph->faces);
2000 if (!face) return E_OUTOFMEMORY;
2001 (*face)[0] = vtx_idx;
2002 (*face)[f1] = last_pt;
2003 (*face)[f2] = last_pt = t->vertex_stack.items[i];
2005 t->vertex_stack.items[0] = last_pt;
2006 t->vertex_stack.count = 1;
2007 } else if (t->vertex_stack.count > 1) {
2008 int i = t->vertex_stack.count - 1;
2009 D3DXVECTOR2 *point = get_ordered_vertex(glyph, vtx_idx);
2010 WORD top_idx = t->vertex_stack.items[i--];
2011 D3DXVECTOR2 *top_pt = get_ordered_vertex(glyph, top_idx);
2015 WORD prev_idx = t->vertex_stack.items[i--];
2016 D3DXVECTOR2 *prev_pt = get_ordered_vertex(glyph, prev_idx);
2018 if (prev_pt->x != top_pt->x &&
2019 ((to_top && get_line_to_point_y_distance(prev_pt, top_pt, point) > 0) ||
2020 (!to_top && get_line_to_point_y_distance(prev_pt, top_pt, point) < 0)))
2023 face = add_face(&glyph->faces);
2024 if (!face) return E_OUTOFMEMORY;
2025 (*face)[0] = vtx_idx;
2026 (*face)[f1] = prev_idx;
2027 (*face)[f2] = top_idx;
2031 t->vertex_stack.count--;
2034 t->last_on_top = to_top;
2036 hr = add_vertex_index(&t->vertex_stack, vtx_idx);
2038 if (hr == S_OK && t->merging) {
2039 struct triangulation *t2;
2041 t2 = to_top ? t - 1 : t + 1;
2042 t2->merging = FALSE;
2043 hr = triangulation_add_point(&t2, triangulations, vtx_idx, to_top);
2044 if (hr != S_OK) return hr;
2045 remove_triangulation(triangulations, t);
2053 /* check if the point is next on the outline for either the top or bottom */
2054 static D3DXVECTOR2 *triangulation_get_next_point(struct triangulation *t, struct glyphinfo *glyph, BOOL on_top)
2056 int i = t->last_on_top == on_top ? t->vertex_stack.count - 1 : 0;
2057 WORD idx = t->vertex_stack.items[i];
2058 struct point2d_index *pt_idx = &glyph->ordered_vertices.items[idx];
2059 struct outline *outline = pt_idx->outline;
2062 i = (pt_idx->vertex + outline->count - 1) % outline->count;
2064 i = (pt_idx->vertex + 1) % outline->count;
2066 return &outline->items[i].pos;
2069 static int compare_vertex_indices(const void *a, const void *b)
2071 const struct point2d_index *idx1 = a, *idx2 = b;
2072 const D3DXVECTOR2 *p1 = &idx1->outline->items[idx1->vertex].pos;
2073 const D3DXVECTOR2 *p2 = &idx2->outline->items[idx2->vertex].pos;
2074 float diff = p1->x - p2->x;
2077 diff = p1->y - p2->y;
2079 return diff == 0.0f ? 0 : (diff > 0.0f ? -1 : 1);
2082 static HRESULT triangulate(struct triangulation_array *triangulations)
2086 struct glyphinfo *glyph = triangulations->glyph;
2087 int nb_vertices = 0;
2089 struct point2d_index *idx_ptr;
2091 for (i = 0; i < glyph->outlines.count; i++)
2092 nb_vertices += glyph->outlines.items[i].count;
2094 glyph->ordered_vertices.items = HeapAlloc(GetProcessHeap(), 0,
2095 nb_vertices * sizeof(*glyph->ordered_vertices.items));
2096 if (!glyph->ordered_vertices.items)
2097 return E_OUTOFMEMORY;
2099 idx_ptr = glyph->ordered_vertices.items;
2100 for (i = 0; i < glyph->outlines.count; i++)
2102 struct outline *outline = &glyph->outlines.items[i];
2105 idx_ptr->outline = outline;
2106 idx_ptr->vertex = 0;
2108 for (j = outline->count - 1; j > 0; j--)
2110 idx_ptr->outline = outline;
2111 idx_ptr->vertex = j;
2115 glyph->ordered_vertices.count = nb_vertices;
2117 /* Native implementation seems to try to create a triangle fan from
2118 * the first outline point if the glyph only has one outline. */
2119 if (glyph->outlines.count == 1)
2121 struct outline *outline = glyph->outlines.items;
2122 D3DXVECTOR2 *base = &outline->items[0].pos;
2123 D3DXVECTOR2 *last = &outline->items[1].pos;
2126 for (i = 2; i < outline->count; i++)
2128 D3DXVECTOR2 *next = &outline->items[i].pos;
2129 D3DXVECTOR2 v1 = {0.0f, 0.0f};
2130 D3DXVECTOR2 v2 = {0.0f, 0.0f};
2132 D3DXVec2Subtract(&v1, base, last);
2133 D3DXVec2Subtract(&v2, last, next);
2134 ccw = D3DXVec2CCW(&v1, &v2);
2142 glyph->faces.items = HeapAlloc(GetProcessHeap(), 0,
2143 (outline->count - 2) * sizeof(glyph->faces.items[0]));
2144 if (!glyph->faces.items)
2145 return E_OUTOFMEMORY;
2147 glyph->faces.count = outline->count - 2;
2148 for (i = 0; i < glyph->faces.count; i++)
2150 glyph->faces.items[i][0] = 0;
2151 glyph->faces.items[i][1] = i + 1;
2152 glyph->faces.items[i][2] = i + 2;
2158 /* Perform 2D polygon triangulation for complex glyphs.
2159 * Triangulation is performed using a sweep line concept, from right to left,
2160 * by processing vertices in sorted order. Complex polygons are split into
2161 * monotone polygons which are triangulated seperately. */
2162 /* FIXME: The order of the faces is not consistent with the native implementation. */
2164 /* Reserve space for maximum possible faces from triangulation.
2165 * # faces for outer outlines = outline->count - 2
2166 * # faces for inner outlines = outline->count + 2
2167 * There must be at least 1 outer outline. */
2168 glyph->faces.items = HeapAlloc(GetProcessHeap(), 0,
2169 (nb_vertices + glyph->outlines.count * 2 - 4) * sizeof(glyph->faces.items[0]));
2170 if (!glyph->faces.items)
2171 return E_OUTOFMEMORY;
2173 qsort(glyph->ordered_vertices.items, nb_vertices,
2174 sizeof(glyph->ordered_vertices.items[0]), compare_vertex_indices);
2175 for (sweep_idx = 0; sweep_idx < glyph->ordered_vertices.count; sweep_idx++)
2178 int end = triangulations->count;
2182 D3DXVECTOR2 *sweep_vtx = get_ordered_vertex(glyph, sweep_idx);
2183 int current = (start + end) / 2;
2184 struct triangulation *t = &triangulations->items[current];
2185 BOOL on_top_outline = FALSE;
2186 D3DXVECTOR2 *top_next, *bottom_next;
2187 WORD top_idx, bottom_idx;
2189 if (t->merging && t->last_on_top)
2190 top_next = triangulation_get_next_point(t + 1, glyph, TRUE);
2192 top_next = triangulation_get_next_point(t, glyph, TRUE);
2193 if (sweep_vtx == top_next)
2195 if (t->merging && t->last_on_top)
2197 hr = triangulation_add_point(&t, triangulations, sweep_idx, TRUE);
2198 if (hr != S_OK) return hr;
2200 if (t + 1 < &triangulations->items[triangulations->count] &&
2201 triangulation_get_next_point(t + 1, glyph, FALSE) == sweep_vtx)
2203 /* point also on bottom outline of higher triangulation */
2204 struct triangulation *t2 = t + 1;
2205 hr = triangulation_add_point(&t2, triangulations, sweep_idx, FALSE);
2206 if (hr != S_OK) return hr;
2211 on_top_outline = TRUE;
2214 if (t->merging && !t->last_on_top)
2215 bottom_next = triangulation_get_next_point(t - 1, glyph, FALSE);
2217 bottom_next = triangulation_get_next_point(t, glyph, FALSE);
2218 if (sweep_vtx == bottom_next)
2220 if (t->merging && !t->last_on_top)
2222 if (on_top_outline) {
2223 /* outline finished */
2224 remove_triangulation(triangulations, t);
2228 hr = triangulation_add_point(&t, triangulations, sweep_idx, FALSE);
2229 if (hr != S_OK) return hr;
2231 if (t > triangulations->items &&
2232 triangulation_get_next_point(t - 1, glyph, TRUE) == sweep_vtx)
2234 struct triangulation *t2 = t - 1;
2235 /* point also on top outline of lower triangulation */
2236 hr = triangulation_add_point(&t2, triangulations, sweep_idx, TRUE);
2237 if (hr != S_OK) return hr;
2238 t = t2 + 1; /* t may be invalidated by triangulation merging */
2248 if (t->last_on_top) {
2249 top_idx = t->vertex_stack.items[t->vertex_stack.count - 1];
2250 bottom_idx = t->vertex_stack.items[0];
2252 top_idx = t->vertex_stack.items[0];
2253 bottom_idx = t->vertex_stack.items[t->vertex_stack.count - 1];
2256 /* check if the point is inside or outside this polygon */
2257 if (get_line_to_point_y_distance(get_ordered_vertex(glyph, top_idx),
2258 top_next, sweep_vtx) > 0)
2260 start = current + 1;
2261 } else if (get_line_to_point_y_distance(get_ordered_vertex(glyph, bottom_idx),
2262 bottom_next, sweep_vtx) < 0)
2265 } else if (t->merging) {
2266 /* inside, so cancel merging */
2267 struct triangulation *t2 = t->last_on_top ? t + 1 : t - 1;
2269 t2->merging = FALSE;
2270 hr = triangulation_add_point(&t, triangulations, sweep_idx, t->last_on_top);
2271 if (hr != S_OK) return hr;
2272 hr = triangulation_add_point(&t2, triangulations, sweep_idx, t2->last_on_top);
2273 if (hr != S_OK) return hr;
2276 /* inside, so split polygon into two monotone parts */
2277 struct triangulation *t2 = add_triangulation(triangulations);
2278 if (!t2) return E_OUTOFMEMORY;
2279 MoveMemory(t + 1, t, (char*)(t2 + 1) - (char*)t);
2280 if (t->last_on_top) {
2287 ZeroMemory(&t2->vertex_stack, sizeof(t2->vertex_stack));
2288 hr = add_vertex_index(&t2->vertex_stack, t->vertex_stack.items[t->vertex_stack.count - 1]);
2289 if (hr != S_OK) return hr;
2290 hr = add_vertex_index(&t2->vertex_stack, sweep_idx);
2291 if (hr != S_OK) return hr;
2292 t2->last_on_top = !t->last_on_top;
2294 hr = triangulation_add_point(&t, triangulations, sweep_idx, t->last_on_top);
2295 if (hr != S_OK) return hr;
2301 struct triangulation *t;
2302 struct triangulation *t2 = add_triangulation(triangulations);
2303 if (!t2) return E_OUTOFMEMORY;
2304 t = &triangulations->items[start];
2305 MoveMemory(t + 1, t, (char*)(t2 + 1) - (char*)t);
2306 ZeroMemory(t, sizeof(*t));
2307 hr = add_vertex_index(&t->vertex_stack, sweep_idx);
2308 if (hr != S_OK) return hr;
2314 HRESULT WINAPI D3DXCreateTextW(LPDIRECT3DDEVICE9 device,
2315 HDC hdc, LPCWSTR text,
2316 FLOAT deviation, FLOAT extrusion,
2317 LPD3DXMESH *mesh_ptr, LPD3DXBUFFER *adjacency,
2318 LPGLYPHMETRICSFLOAT glyphmetrics)
2321 ID3DXMesh *mesh = NULL;
2322 DWORD nb_vertices, nb_faces;
2323 DWORD nb_front_faces, nb_corners, nb_outline_points;
2324 struct vertex *vertices = NULL;
2329 OUTLINETEXTMETRICW otm;
2330 HFONT font = NULL, oldfont = NULL;
2331 const MAT2 identity = {{0, 1}, {0, 0}, {0, 0}, {0, 1}};
2332 void *raw_outline = NULL;
2334 struct glyphinfo *glyphs = NULL;
2336 struct triangulation_array triangulations = {0, 0, NULL};
2338 struct vertex *vertex_ptr;
2340 float max_deviation_sq;
2341 const struct cos_table cos_table = {
2342 cos(D3DXToRadian(0.5f)),
2343 cos(D3DXToRadian(45.0f)),
2344 cos(D3DXToRadian(90.0f)),
2348 TRACE("(%p, %p, %s, %f, %f, %p, %p, %p)\n", device, hdc,
2349 debugstr_w(text), deviation, extrusion, mesh_ptr, adjacency, glyphmetrics);
2351 if (!device || !hdc || !text || !*text || deviation < 0.0f || extrusion < 0.0f || !mesh_ptr)
2352 return D3DERR_INVALIDCALL;
2356 FIXME("Case of adjacency != NULL not implemented.\n");
2360 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf) ||
2361 !GetOutlineTextMetricsW(hdc, sizeof(otm), &otm))
2363 return D3DERR_INVALIDCALL;
2366 if (deviation == 0.0f)
2367 deviation = 1.0f / otm.otmEMSquare;
2368 max_deviation_sq = deviation * deviation;
2370 lf.lfHeight = otm.otmEMSquare;
2372 font = CreateFontIndirectW(&lf);
2377 oldfont = SelectObject(hdc, font);
2379 textlen = strlenW(text);
2380 for (i = 0; i < textlen; i++)
2382 int datasize = GetGlyphOutlineW(hdc, text[i], GGO_NATIVE, &gm, 0, NULL, &identity);
2384 return D3DERR_INVALIDCALL;
2385 if (bufsize < datasize)
2388 if (!bufsize) { /* e.g. text == " " */
2389 hr = D3DERR_INVALIDCALL;
2393 glyphs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, textlen * sizeof(*glyphs));
2394 raw_outline = HeapAlloc(GetProcessHeap(), 0, bufsize);
2395 if (!glyphs || !raw_outline) {
2401 for (i = 0; i < textlen; i++)
2403 /* get outline points from data returned from GetGlyphOutline */
2406 glyphs[i].offset_x = offset_x;
2408 datasize = GetGlyphOutlineW(hdc, text[i], GGO_NATIVE, &gm, bufsize, raw_outline, &identity);
2409 hr = create_outline(&glyphs[i], raw_outline, datasize,
2410 max_deviation_sq, otm.otmEMSquare, &cos_table);
2411 if (hr != S_OK) goto error;
2413 triangulations.glyph = &glyphs[i];
2414 hr = triangulate(&triangulations);
2415 if (hr != S_OK) goto error;
2416 if (triangulations.count) {
2417 ERR("%d incomplete triangulations of glyph (%u).\n", triangulations.count, text[i]);
2418 triangulations.count = 0;
2423 glyphmetrics[i].gmfBlackBoxX = gm.gmBlackBoxX / (float)otm.otmEMSquare;
2424 glyphmetrics[i].gmfBlackBoxY = gm.gmBlackBoxY / (float)otm.otmEMSquare;
2425 glyphmetrics[i].gmfptGlyphOrigin.x = gm.gmptGlyphOrigin.x / (float)otm.otmEMSquare;
2426 glyphmetrics[i].gmfptGlyphOrigin.y = gm.gmptGlyphOrigin.y / (float)otm.otmEMSquare;
2427 glyphmetrics[i].gmfCellIncX = gm.gmCellIncX / (float)otm.otmEMSquare;
2428 glyphmetrics[i].gmfCellIncY = gm.gmCellIncY / (float)otm.otmEMSquare;
2430 offset_x += gm.gmCellIncX / (float)otm.otmEMSquare;
2433 /* corner points need an extra vertex for the different side faces normals */
2435 nb_outline_points = 0;
2437 for (i = 0; i < textlen; i++)
2440 nb_outline_points += glyphs[i].ordered_vertices.count;
2441 nb_front_faces += glyphs[i].faces.count;
2442 for (j = 0; j < glyphs[i].outlines.count; j++)
2445 struct outline *outline = &glyphs[i].outlines.items[j];
2446 nb_corners++; /* first outline point always repeated as a corner */
2447 for (k = 1; k < outline->count; k++)
2448 if (outline->items[k].corner)
2453 nb_vertices = (nb_outline_points + nb_corners) * 2 + nb_outline_points * 2;
2454 nb_faces = nb_outline_points * 2 + nb_front_faces * 2;
2457 hr = D3DXCreateMeshFVF(nb_faces, nb_vertices, D3DXMESH_MANAGED,
2458 D3DFVF_XYZ | D3DFVF_NORMAL, device, &mesh);
2462 hr = mesh->lpVtbl->LockVertexBuffer(mesh, D3DLOCK_DISCARD, (LPVOID *)&vertices);
2466 hr = mesh->lpVtbl->LockIndexBuffer(mesh, D3DLOCK_DISCARD, (LPVOID *)&faces);
2470 /* convert 2D vertices and faces into 3D mesh */
2471 vertex_ptr = vertices;
2473 if (extrusion == 0.0f) {
2480 for (i = 0; i < textlen; i++)
2484 struct vertex *back_vertices;
2487 /* side vertices and faces */
2488 for (j = 0; j < glyphs[i].outlines.count; j++)
2490 struct vertex *outline_vertices = vertex_ptr;
2491 struct outline *outline = &glyphs[i].outlines.items[j];
2493 struct point2d *prevpt = &outline->items[outline->count - 1];
2494 struct point2d *pt = &outline->items[0];
2496 for (k = 1; k <= outline->count; k++)
2499 struct point2d *nextpt = &outline->items[k % outline->count];
2500 WORD vtx_idx = vertex_ptr - vertices;
2503 if (pt->corner == POINTTYPE_CURVE_START)
2504 D3DXVec2Subtract(&vec, &pt->pos, &prevpt->pos);
2505 else if (pt->corner)
2506 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
2508 D3DXVec2Subtract(&vec, &nextpt->pos, &prevpt->pos);
2509 D3DXVec2Normalize(&vec, &vec);
2510 vtx.normal.x = -vec.y;
2511 vtx.normal.y = vec.x;
2514 vtx.position.x = pt->pos.x + glyphs[i].offset_x;
2515 vtx.position.y = pt->pos.y;
2517 *vertex_ptr++ = vtx;
2519 vtx.position.z = -extrusion;
2520 *vertex_ptr++ = vtx;
2522 vtx.position.x = nextpt->pos.x + glyphs[i].offset_x;
2523 vtx.position.y = nextpt->pos.y;
2524 if (pt->corner && nextpt->corner && nextpt->corner != POINTTYPE_CURVE_END) {
2525 vtx.position.z = -extrusion;
2526 *vertex_ptr++ = vtx;
2528 *vertex_ptr++ = vtx;
2530 (*face_ptr)[0] = vtx_idx;
2531 (*face_ptr)[1] = vtx_idx + 2;
2532 (*face_ptr)[2] = vtx_idx + 1;
2535 (*face_ptr)[0] = vtx_idx;
2536 (*face_ptr)[1] = vtx_idx + 3;
2537 (*face_ptr)[2] = vtx_idx + 2;
2540 if (nextpt->corner) {
2541 if (nextpt->corner == POINTTYPE_CURVE_END) {
2542 D3DXVECTOR2 *nextpt2 = &outline->items[(k + 1) % outline->count].pos;
2543 D3DXVec2Subtract(&vec, nextpt2, &nextpt->pos);
2545 D3DXVec2Subtract(&vec, &nextpt->pos, &pt->pos);
2547 D3DXVec2Normalize(&vec, &vec);
2548 vtx.normal.x = -vec.y;
2549 vtx.normal.y = vec.x;
2552 *vertex_ptr++ = vtx;
2553 vtx.position.z = -extrusion;
2554 *vertex_ptr++ = vtx;
2557 (*face_ptr)[0] = vtx_idx;
2558 (*face_ptr)[1] = vtx_idx + 3;
2559 (*face_ptr)[2] = vtx_idx + 1;
2562 (*face_ptr)[0] = vtx_idx;
2563 (*face_ptr)[1] = vtx_idx + 2;
2564 (*face_ptr)[2] = vtx_idx + 3;
2572 *vertex_ptr++ = *outline_vertices++;
2573 *vertex_ptr++ = *outline_vertices++;
2577 /* back vertices and faces */
2578 back_faces = face_ptr;
2579 back_vertices = vertex_ptr;
2580 for (j = 0; j < glyphs[i].ordered_vertices.count; j++)
2582 D3DXVECTOR2 *pt = get_ordered_vertex(&glyphs[i], j);
2583 vertex_ptr->position.x = pt->x + glyphs[i].offset_x;
2584 vertex_ptr->position.y = pt->y;
2585 vertex_ptr->position.z = 0;
2586 vertex_ptr->normal.x = 0;
2587 vertex_ptr->normal.y = 0;
2588 vertex_ptr->normal.z = 1;
2591 count = back_vertices - vertices;
2592 for (j = 0; j < glyphs[i].faces.count; j++)
2594 face *f = &glyphs[i].faces.items[j];
2595 (*face_ptr)[0] = (*f)[0] + count;
2596 (*face_ptr)[1] = (*f)[1] + count;
2597 (*face_ptr)[2] = (*f)[2] + count;
2601 /* front vertices and faces */
2602 j = count = vertex_ptr - back_vertices;
2605 vertex_ptr->position.x = back_vertices->position.x;
2606 vertex_ptr->position.y = back_vertices->position.y;
2607 vertex_ptr->position.z = -extrusion;
2608 vertex_ptr->normal.x = 0;
2609 vertex_ptr->normal.y = 0;
2610 vertex_ptr->normal.z = extrusion == 0.0f ? 1.0f : -1.0f;
2614 j = face_ptr - back_faces;
2617 (*face_ptr)[0] = (*back_faces)[0] + count;
2618 (*face_ptr)[1] = (*back_faces)[f1] + count;
2619 (*face_ptr)[2] = (*back_faces)[f2] + count;
2629 if (faces) mesh->lpVtbl->UnlockIndexBuffer(mesh);
2630 if (vertices) mesh->lpVtbl->UnlockVertexBuffer(mesh);
2631 if (hr != D3D_OK) mesh->lpVtbl->Release(mesh);
2634 for (i = 0; i < textlen; i++)
2637 for (j = 0; j < glyphs[i].outlines.count; j++)
2638 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items[j].items);
2639 HeapFree(GetProcessHeap(), 0, glyphs[i].outlines.items);
2640 HeapFree(GetProcessHeap(), 0, glyphs[i].faces.items);
2641 HeapFree(GetProcessHeap(), 0, glyphs[i].ordered_vertices.items);
2643 HeapFree(GetProcessHeap(), 0, glyphs);
2645 if (triangulations.items) {
2647 for (i = 0; i < triangulations.count; i++)
2648 HeapFree(GetProcessHeap(), 0, triangulations.items[i].vertex_stack.items);
2649 HeapFree(GetProcessHeap(), 0, triangulations.items);
2651 HeapFree(GetProcessHeap(), 0, raw_outline);
2652 if (oldfont) SelectObject(hdc, oldfont);
2653 if (font) DeleteObject(font);