user32: Propagate the LoadImage flags into the low-level loader functions.
[wine.git] / dlls / d3dx9_36 / mesh.c
blob6a74442482f6360ac45551bcbd0f93eb47c0ac4a
1 /*
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
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "config.h"
25 #include "wine/port.h"
27 #define NONAMELESSUNION
28 #include "windef.h"
29 #include "wingdi.h"
30 #include "d3dx9.h"
31 #include "wine/debug.h"
32 #include "d3dx9_36_private.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
36 typedef struct ID3DXMeshImpl
38 ID3DXMesh ID3DXMesh_iface;
39 LONG ref;
41 DWORD numfaces;
42 DWORD numvertices;
43 DWORD options;
44 DWORD fvf;
45 IDirect3DDevice9 *device;
46 IDirect3DVertexDeclaration9 *vertex_declaration;
47 IDirect3DVertexBuffer9 *vertex_buffer;
48 IDirect3DIndexBuffer9 *index_buffer;
49 } ID3DXMeshImpl;
51 static inline ID3DXMeshImpl *impl_from_ID3DXMesh(ID3DXMesh *iface)
53 return CONTAINING_RECORD(iface, ID3DXMeshImpl, ID3DXMesh_iface);
56 static HRESULT WINAPI ID3DXMeshImpl_QueryInterface(ID3DXMesh *iface, REFIID riid, LPVOID *object)
58 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
60 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), object);
62 if (IsEqualGUID(riid, &IID_IUnknown) ||
63 IsEqualGUID(riid, &IID_ID3DXBaseMesh) ||
64 IsEqualGUID(riid, &IID_ID3DXMesh))
66 iface->lpVtbl->AddRef(iface);
67 *object = This;
68 return S_OK;
71 WARN("Interface %s not found.\n", debugstr_guid(riid));
73 return E_NOINTERFACE;
76 static ULONG WINAPI ID3DXMeshImpl_AddRef(ID3DXMesh *iface)
78 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
80 TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
82 return InterlockedIncrement(&This->ref);
85 static ULONG WINAPI ID3DXMeshImpl_Release(ID3DXMesh *iface)
87 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
88 ULONG ref = InterlockedDecrement(&This->ref);
90 TRACE("(%p)->(): Release from %d\n", This, ref + 1);
92 if (!ref)
94 IDirect3DIndexBuffer9_Release(This->index_buffer);
95 IDirect3DVertexBuffer9_Release(This->vertex_buffer);
96 IDirect3DVertexDeclaration9_Release(This->vertex_declaration);
97 IDirect3DDevice9_Release(This->device);
98 HeapFree(GetProcessHeap(), 0, This);
101 return ref;
104 /*** ID3DXBaseMesh ***/
105 static HRESULT WINAPI ID3DXMeshImpl_DrawSubset(ID3DXMesh *iface, DWORD attrib_id)
107 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
109 FIXME("(%p)->(%u): stub\n", This, attrib_id);
111 return E_NOTIMPL;
114 static DWORD WINAPI ID3DXMeshImpl_GetNumFaces(ID3DXMesh *iface)
116 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
118 TRACE("(%p)\n", This);
120 return This->numfaces;
123 static DWORD WINAPI ID3DXMeshImpl_GetNumVertices(ID3DXMesh *iface)
125 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
127 TRACE("(%p)\n", This);
129 return This->numvertices;
132 static DWORD WINAPI ID3DXMeshImpl_GetFVF(ID3DXMesh *iface)
134 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
136 TRACE("(%p)\n", This);
138 return This->fvf;
141 static HRESULT WINAPI ID3DXMeshImpl_GetDeclaration(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
143 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
144 UINT numelements;
146 TRACE("(%p)\n", This);
148 if (declaration == NULL) return D3DERR_INVALIDCALL;
150 return IDirect3DVertexDeclaration9_GetDeclaration(This->vertex_declaration,
151 declaration,
152 &numelements);
155 static DWORD WINAPI ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh *iface)
157 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
159 FIXME("(%p): stub\n", This);
161 return 0; /* arbitrary since we cannot return E_NOTIMPL */
164 static DWORD WINAPI ID3DXMeshImpl_GetOptions(ID3DXMesh *iface)
166 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
168 TRACE("(%p)\n", This);
170 return This->options;
173 static HRESULT WINAPI ID3DXMeshImpl_GetDevice(ID3DXMesh *iface, LPDIRECT3DDEVICE9 *device)
175 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
177 TRACE("(%p)->(%p)\n", This, device);
179 if (device == NULL) return D3DERR_INVALIDCALL;
180 *device = This->device;
181 IDirect3DDevice9_AddRef(This->device);
183 return D3D_OK;
186 static HRESULT WINAPI ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh *iface, DWORD options, DWORD fvf, LPDIRECT3DDEVICE9 device, LPD3DXMESH *clone_mesh)
188 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
190 FIXME("(%p)->(%u,%u,%p,%p): stub\n", This, options, fvf, device, clone_mesh);
192 return E_NOTIMPL;
195 static HRESULT WINAPI ID3DXMeshImpl_CloneMesh(ID3DXMesh *iface, DWORD options, CONST D3DVERTEXELEMENT9 *declaration, LPDIRECT3DDEVICE9 device,
196 LPD3DXMESH *clone_mesh)
198 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
200 FIXME("(%p)->(%u,%p,%p,%p): stub\n", This, options, declaration, device, clone_mesh);
202 return E_NOTIMPL;
205 static HRESULT WINAPI ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh *iface, LPDIRECT3DVERTEXBUFFER9 *vertex_buffer)
207 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
209 TRACE("(%p)->(%p)\n", This, vertex_buffer);
211 if (vertex_buffer == NULL) return D3DERR_INVALIDCALL;
212 *vertex_buffer = This->vertex_buffer;
213 IDirect3DVertexBuffer9_AddRef(This->vertex_buffer);
215 return D3D_OK;
218 static HRESULT WINAPI ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh *iface, LPDIRECT3DINDEXBUFFER9 *index_buffer)
220 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
222 TRACE("(%p)->(%p)\n", This, index_buffer);
224 if (index_buffer == NULL) return D3DERR_INVALIDCALL;
225 *index_buffer = This->index_buffer;
226 IDirect3DIndexBuffer9_AddRef(This->index_buffer);
228 return D3D_OK;
231 static HRESULT WINAPI ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
233 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
235 TRACE("(%p)->(%u,%p)\n", This, flags, data);
237 return IDirect3DVertexBuffer9_Lock(This->vertex_buffer, 0, 0, data, flags);
240 static HRESULT WINAPI ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh *iface)
242 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
244 TRACE("(%p)\n", This);
246 return IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
249 static HRESULT WINAPI ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
251 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
253 TRACE("(%p)->(%u,%p)\n", This, flags, data);
255 return IDirect3DIndexBuffer9_Lock(This->index_buffer, 0, 0, data, flags);
258 static HRESULT WINAPI ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh *iface)
260 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
262 TRACE("(%p)\n", This);
264 return IDirect3DIndexBuffer9_Unlock(This->index_buffer);
267 static HRESULT WINAPI ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTRIBUTERANGE *attrib_table, DWORD *attrib_table_size)
269 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
271 FIXME("(%p)->(%p,%p): stub\n", This, attrib_table, attrib_table_size);
273 return E_NOTIMPL;
276 static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency)
278 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
280 FIXME("(%p)->(%p,%p): stub\n", This, point_reps, adjacency);
282 return E_NOTIMPL;
285 static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, CONST DWORD *adjacency, DWORD *point_reps)
287 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
289 FIXME("(%p)->(%p,%p): stub\n", This, adjacency, point_reps);
291 return E_NOTIMPL;
294 static HRESULT WINAPI ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh *iface, FLOAT epsilon, DWORD *adjacency)
296 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
298 FIXME("(%p)->(%f,%p): stub\n", This, epsilon, adjacency);
300 return E_NOTIMPL;
303 static HRESULT WINAPI ID3DXMeshImpl_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
305 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
307 FIXME("(%p)->(%p): stub\n", This, declaration);
309 return E_NOTIMPL;
312 /*** ID3DXMesh ***/
313 static HRESULT WINAPI ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh *iface, DWORD flags, DWORD **data)
315 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
317 FIXME("(%p)->(%u,%p): stub\n", This, flags, data);
319 return E_NOTIMPL;
322 static HRESULT WINAPI ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh *iface)
324 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
326 FIXME("(%p): stub\n", This);
328 return E_NOTIMPL;
331 static HRESULT WINAPI ID3DXMeshImpl_Optimize(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
332 DWORD *face_remap, LPD3DXBUFFER *vertex_remap, LPD3DXMESH *opt_mesh)
334 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
336 FIXME("(%p)->(%u,%p,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap, opt_mesh);
338 return E_NOTIMPL;
341 static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
342 DWORD *face_remap, LPD3DXBUFFER *vertex_remap)
344 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
346 FIXME("(%p)->(%u,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap);
348 return E_NOTIMPL;
351 static HRESULT WINAPI ID3DXMeshImpl_SetAttributeTable(ID3DXMesh *iface, CONST D3DXATTRIBUTERANGE *attrib_table, DWORD attrib_table_size)
353 ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
355 FIXME("(%p)->(%p,%u): stub\n", This, attrib_table, attrib_table_size);
357 return E_NOTIMPL;
360 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl =
362 /*** IUnknown methods ***/
363 ID3DXMeshImpl_QueryInterface,
364 ID3DXMeshImpl_AddRef,
365 ID3DXMeshImpl_Release,
366 /*** ID3DXBaseMesh ***/
367 ID3DXMeshImpl_DrawSubset,
368 ID3DXMeshImpl_GetNumFaces,
369 ID3DXMeshImpl_GetNumVertices,
370 ID3DXMeshImpl_GetFVF,
371 ID3DXMeshImpl_GetDeclaration,
372 ID3DXMeshImpl_GetNumBytesPerVertex,
373 ID3DXMeshImpl_GetOptions,
374 ID3DXMeshImpl_GetDevice,
375 ID3DXMeshImpl_CloneMeshFVF,
376 ID3DXMeshImpl_CloneMesh,
377 ID3DXMeshImpl_GetVertexBuffer,
378 ID3DXMeshImpl_GetIndexBuffer,
379 ID3DXMeshImpl_LockVertexBuffer,
380 ID3DXMeshImpl_UnlockVertexBuffer,
381 ID3DXMeshImpl_LockIndexBuffer,
382 ID3DXMeshImpl_UnlockIndexBuffer,
383 ID3DXMeshImpl_GetAttributeTable,
384 ID3DXMeshImpl_ConvertPointRepsToAdjacency,
385 ID3DXMeshImpl_ConvertAdjacencyToPointReps,
386 ID3DXMeshImpl_GenerateAdjacency,
387 ID3DXMeshImpl_UpdateSemantics,
388 /*** ID3DXMesh ***/
389 ID3DXMeshImpl_LockAttributeBuffer,
390 ID3DXMeshImpl_UnlockAttributeBuffer,
391 ID3DXMeshImpl_Optimize,
392 ID3DXMeshImpl_OptimizeInplace,
393 ID3DXMeshImpl_SetAttributeTable
396 /*************************************************************************
397 * D3DXBoxBoundProbe
399 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
401 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
402 Amy Williams University of Utah
403 Steve Barrus University of Utah
404 R. Keith Morley University of Utah
405 Peter Shirley University of Utah
407 International Conference on Computer Graphics and Interactive Techniques archive
408 ACM SIGGRAPH 2005 Courses
409 Los Angeles, California
411 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
413 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
414 against each slab, if there's anything left of the ray after we're
415 done we've got an intersection of the ray with the box.
419 FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
421 div = 1.0f / praydirection->x;
422 if ( div >= 0.0f )
424 tmin = ( pmin->x - prayposition->x ) * div;
425 tmax = ( pmax->x - prayposition->x ) * div;
427 else
429 tmin = ( pmax->x - prayposition->x ) * div;
430 tmax = ( pmin->x - prayposition->x ) * div;
433 if ( tmax < 0.0f ) return FALSE;
435 div = 1.0f / praydirection->y;
436 if ( div >= 0.0f )
438 tymin = ( pmin->y - prayposition->y ) * div;
439 tymax = ( pmax->y - prayposition->y ) * div;
441 else
443 tymin = ( pmax->y - prayposition->y ) * div;
444 tymax = ( pmin->y - prayposition->y ) * div;
447 if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
449 if ( tymin > tmin ) tmin = tymin;
450 if ( tymax < tmax ) tmax = tymax;
452 div = 1.0f / praydirection->z;
453 if ( div >= 0.0f )
455 tzmin = ( pmin->z - prayposition->z ) * div;
456 tzmax = ( pmax->z - prayposition->z ) * div;
458 else
460 tzmin = ( pmax->z - prayposition->z ) * div;
461 tzmax = ( pmin->z - prayposition->z ) * div;
464 if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
466 return TRUE;
469 /*************************************************************************
470 * D3DXComputeBoundingBox
472 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
474 D3DXVECTOR3 vec;
475 unsigned int i;
477 if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
479 *pmin = *pfirstposition;
480 *pmax = *pmin;
482 for(i=0; i<numvertices; i++)
484 vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
486 if ( vec.x < pmin->x ) pmin->x = vec.x;
487 if ( vec.x > pmax->x ) pmax->x = vec.x;
489 if ( vec.y < pmin->y ) pmin->y = vec.y;
490 if ( vec.y > pmax->y ) pmax->y = vec.y;
492 if ( vec.z < pmin->z ) pmin->z = vec.z;
493 if ( vec.z > pmax->z ) pmax->z = vec.z;
496 return D3D_OK;
499 /*************************************************************************
500 * D3DXComputeBoundingSphere
502 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
504 D3DXVECTOR3 temp, temp1;
505 FLOAT d;
506 unsigned int i;
508 if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
510 temp.x = 0.0f;
511 temp.y = 0.0f;
512 temp.z = 0.0f;
513 temp1 = temp;
514 d = 0.0f;
515 *pradius = 0.0f;
517 for(i=0; i<numvertices; i++)
519 D3DXVec3Add(&temp1, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
520 temp = temp1;
523 D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
525 for(i=0; i<numvertices; i++)
527 d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
528 if ( d > *pradius ) *pradius = d;
530 return D3D_OK;
533 static const UINT d3dx_decltype_size[D3DDECLTYPE_UNUSED] =
535 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
536 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
537 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
538 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
539 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
540 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
541 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
542 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
543 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
544 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
545 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
546 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
547 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
548 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
549 /* D3DDECLTYPE_DEC3N */ 4,
550 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
551 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
554 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
555 D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
557 declaration[*idx].Stream = 0;
558 declaration[*idx].Offset = *offset;
559 declaration[*idx].Type = type;
560 declaration[*idx].Method = D3DDECLMETHOD_DEFAULT;
561 declaration[*idx].Usage = usage;
562 declaration[*idx].UsageIndex = usage_idx;
564 *offset += d3dx_decltype_size[type];
565 ++(*idx);
568 /*************************************************************************
569 * D3DXDeclaratorFromFVF
571 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
573 static const D3DVERTEXELEMENT9 end_element = D3DDECL_END();
574 DWORD tex_count = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
575 unsigned int offset = 0;
576 unsigned int idx = 0;
577 unsigned int i;
579 TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
581 if (fvf & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) return D3DERR_INVALIDCALL;
583 if (fvf & D3DFVF_POSITION_MASK)
585 BOOL has_blend = (fvf & D3DFVF_XYZB5) >= D3DFVF_XYZB1;
586 DWORD blend_count = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
587 BOOL has_blend_idx = (fvf & D3DFVF_LASTBETA_D3DCOLOR) || (fvf & D3DFVF_LASTBETA_UBYTE4);
589 if (has_blend_idx) --blend_count;
591 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
592 || (has_blend && blend_count > 4))
593 return D3DERR_INVALIDCALL;
595 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
596 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_POSITIONT, 0);
597 else
598 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_POSITION, 0);
600 if (has_blend)
602 switch (blend_count)
604 case 0:
605 break;
606 case 1:
607 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_BLENDWEIGHT, 0);
608 break;
609 case 2:
610 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_BLENDWEIGHT, 0);
611 break;
612 case 3:
613 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_BLENDWEIGHT, 0);
614 break;
615 case 4:
616 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_BLENDWEIGHT, 0);
617 break;
618 default:
619 ERR("Invalid blend count %u.\n", blend_count);
620 break;
623 if (has_blend_idx)
625 if (fvf & D3DFVF_LASTBETA_UBYTE4)
626 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_UBYTE4, D3DDECLUSAGE_BLENDINDICES, 0);
627 else if (fvf & D3DFVF_LASTBETA_D3DCOLOR)
628 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_BLENDINDICES, 0);
633 if (fvf & D3DFVF_NORMAL)
634 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_NORMAL, 0);
635 if (fvf & D3DFVF_PSIZE)
636 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_PSIZE, 0);
637 if (fvf & D3DFVF_DIFFUSE)
638 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 0);
639 if (fvf & D3DFVF_SPECULAR)
640 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 1);
642 for (i = 0; i < tex_count; ++i)
644 switch ((fvf >> (16 + 2 * i)) & 0x03)
646 case D3DFVF_TEXTUREFORMAT1:
647 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_TEXCOORD, i);
648 break;
649 case D3DFVF_TEXTUREFORMAT2:
650 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_TEXCOORD, i);
651 break;
652 case D3DFVF_TEXTUREFORMAT3:
653 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_TEXCOORD, i);
654 break;
655 case D3DFVF_TEXTUREFORMAT4:
656 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_TEXCOORD, i);
657 break;
661 declaration[idx] = end_element;
663 return D3D_OK;
666 /*************************************************************************
667 * D3DXFVFFromDeclarator
669 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
671 unsigned int i = 0, texture, offset;
673 TRACE("(%p, %p)\n", declaration, fvf);
675 *fvf = 0;
676 if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
678 if ((declaration[1].Type == D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
679 declaration[1].UsageIndex == 0) &&
680 (declaration[2].Type == D3DDECLTYPE_FLOAT1 && declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES &&
681 declaration[2].UsageIndex == 0))
683 return D3DERR_INVALIDCALL;
685 else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
686 declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
688 if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
690 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
692 else
694 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
696 i = 2;
698 else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
699 declaration[1].UsageIndex == 0)
701 if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
702 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
704 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
706 *fvf |= D3DFVF_LASTBETA_UBYTE4;
708 else
710 *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
712 switch (declaration[1].Type)
714 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB2; break;
715 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB3; break;
716 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB4; break;
717 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB5; break;
719 i = 3;
721 else
723 switch (declaration[1].Type)
725 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB1; break;
726 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB2; break;
727 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB3; break;
728 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB4; break;
730 i = 2;
733 else
735 *fvf |= D3DFVF_XYZ;
736 i = 1;
739 else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
740 declaration[0].UsageIndex == 0)
742 *fvf |= D3DFVF_XYZRHW;
743 i = 1;
746 if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
748 *fvf |= D3DFVF_NORMAL;
749 i++;
751 if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
752 declaration[i].UsageIndex == 0)
754 *fvf |= D3DFVF_PSIZE;
755 i++;
757 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
758 declaration[i].UsageIndex == 0)
760 *fvf |= D3DFVF_DIFFUSE;
761 i++;
763 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
764 declaration[i].UsageIndex == 1)
766 *fvf |= D3DFVF_SPECULAR;
767 i++;
770 for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
772 if (declaration[i].Stream == 0xFF)
774 break;
776 else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
777 declaration[i].UsageIndex == texture)
779 *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
781 else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
782 declaration[i].UsageIndex == texture)
784 *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
786 else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
787 declaration[i].UsageIndex == texture)
789 *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
791 else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
792 declaration[i].UsageIndex == texture)
794 *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
796 else
798 return D3DERR_INVALIDCALL;
802 *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
804 for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
805 offset += d3dx_decltype_size[declaration[i].Type], i++)
807 if (declaration[i].Offset != offset)
809 return D3DERR_INVALIDCALL;
813 return D3D_OK;
816 /*************************************************************************
817 * D3DXGetFVFVertexSize
819 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
821 return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
824 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
826 DWORD size = 0;
827 UINT i;
828 UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
830 if (FVF & D3DFVF_NORMAL) size += sizeof(D3DXVECTOR3);
831 if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
832 if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
833 if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
835 switch (FVF & D3DFVF_POSITION_MASK)
837 case D3DFVF_XYZ: size += sizeof(D3DXVECTOR3); break;
838 case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
839 case D3DFVF_XYZB1: size += 4 * sizeof(FLOAT); break;
840 case D3DFVF_XYZB2: size += 5 * sizeof(FLOAT); break;
841 case D3DFVF_XYZB3: size += 6 * sizeof(FLOAT); break;
842 case D3DFVF_XYZB4: size += 7 * sizeof(FLOAT); break;
843 case D3DFVF_XYZB5: size += 8 * sizeof(FLOAT); break;
844 case D3DFVF_XYZW: size += 4 * sizeof(FLOAT); break;
847 for (i = 0; i < numTextures; i++)
849 size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
852 return size;
855 /*************************************************************************
856 * D3DXGetDeclVertexSize
858 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
860 const D3DVERTEXELEMENT9 *element;
861 UINT size = 0;
863 TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
865 if (!decl) return 0;
867 for (element = decl; element->Stream != 0xff; ++element)
869 UINT type_size;
871 if (element->Stream != stream_idx) continue;
873 if (element->Type >= sizeof(d3dx_decltype_size) / sizeof(*d3dx_decltype_size))
875 FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
876 continue;
879 type_size = d3dx_decltype_size[element->Type];
880 if (element->Offset + type_size > size) size = element->Offset + type_size;
883 return size;
886 /*************************************************************************
887 * D3DXGetDeclLength
889 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
891 const D3DVERTEXELEMENT9 *element;
893 TRACE("decl %p\n", decl);
895 /* null decl results in exception on Windows XP */
897 for (element = decl; element->Stream != 0xff; ++element);
899 return element - decl;
902 /*************************************************************************
903 * D3DXIntersectTri
905 BOOL WINAPI D3DXIntersectTri(CONST D3DXVECTOR3 *p0, CONST D3DXVECTOR3 *p1, CONST D3DXVECTOR3 *p2, CONST D3DXVECTOR3 *praypos, CONST D3DXVECTOR3 *praydir, FLOAT *pu, FLOAT *pv, FLOAT *pdist)
907 D3DXMATRIX m;
908 D3DXVECTOR4 vec;
910 m.u.m[0][0] = p1->x - p0->x;
911 m.u.m[1][0] = p2->x - p0->x;
912 m.u.m[2][0] = -praydir->x;
913 m.u.m[3][0] = 0.0f;
914 m.u.m[0][1] = p1->y - p0->z;
915 m.u.m[1][1] = p2->y - p0->z;
916 m.u.m[2][1] = -praydir->y;
917 m.u.m[3][1] = 0.0f;
918 m.u.m[0][2] = p1->z - p0->z;
919 m.u.m[1][2] = p2->z - p0->z;
920 m.u.m[2][2] = -praydir->z;
921 m.u.m[3][2] = 0.0f;
922 m.u.m[0][3] = 0.0f;
923 m.u.m[1][3] = 0.0f;
924 m.u.m[2][3] = 0.0f;
925 m.u.m[3][3] = 1.0f;
927 vec.x = praypos->x - p0->x;
928 vec.y = praypos->y - p0->y;
929 vec.z = praypos->z - p0->z;
930 vec.w = 0.0f;
932 if ( D3DXMatrixInverse(&m, NULL, &m) )
934 D3DXVec4Transform(&vec, &vec, &m);
935 if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
937 *pu = vec.x;
938 *pv = vec.y;
939 *pdist = fabs( vec.z );
940 return TRUE;
944 return FALSE;
947 /*************************************************************************
948 * D3DXSphereBoundProbe
950 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
952 D3DXVECTOR3 difference;
953 FLOAT a, b, c, d;
955 a = D3DXVec3LengthSq(praydirection);
956 if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
957 b = D3DXVec3Dot(&difference, praydirection);
958 c = D3DXVec3LengthSq(&difference) - radius * radius;
959 d = b * b - a * c;
961 if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
962 return TRUE;
965 /*************************************************************************
966 * D3DXCreateMesh
968 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options, CONST D3DVERTEXELEMENT9 *declaration,
969 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
971 HRESULT hr;
972 DWORD fvf;
973 IDirect3DVertexDeclaration9 *vertex_declaration;
974 IDirect3DVertexBuffer9 *vertex_buffer;
975 IDirect3DIndexBuffer9 *index_buffer;
976 ID3DXMeshImpl *object;
978 TRACE("(%d, %d, %d, %p, %p, %p)\n", numfaces, numvertices, options, declaration, device, mesh);
980 if (numfaces == 0 || numvertices == 0 || declaration == NULL || device == NULL || mesh == NULL)
982 return D3DERR_INVALIDCALL;
985 hr = D3DXFVFFromDeclarator(declaration, &fvf);
986 if (hr != D3D_OK)
988 fvf = 0;
991 /* Create vertex declaration */
992 hr = IDirect3DDevice9_CreateVertexDeclaration(device,
993 declaration,
994 &vertex_declaration);
995 if (FAILED(hr))
997 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
998 return hr;
1001 /* Create vertex buffer */
1002 hr = IDirect3DDevice9_CreateVertexBuffer(device,
1003 numvertices * D3DXGetDeclVertexSize(declaration, declaration[0].Stream),
1005 fvf,
1006 D3DPOOL_MANAGED,
1007 &vertex_buffer,
1008 NULL);
1009 if (FAILED(hr))
1011 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1012 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1013 return hr;
1016 /* Create index buffer */
1017 hr = IDirect3DDevice9_CreateIndexBuffer(device,
1018 numfaces * 6, /* 3 vertices per triangle, 2 triangles per face */
1020 D3DFMT_INDEX16,
1021 D3DPOOL_MANAGED,
1022 &index_buffer,
1023 NULL);
1024 if (FAILED(hr))
1026 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1027 IDirect3DVertexBuffer9_Release(vertex_buffer);
1028 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1029 return hr;
1032 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXMeshImpl));
1033 if (object == NULL)
1035 IDirect3DIndexBuffer9_Release(index_buffer);
1036 IDirect3DVertexBuffer9_Release(vertex_buffer);
1037 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1038 *mesh = NULL;
1039 return E_OUTOFMEMORY;
1041 object->ID3DXMesh_iface.lpVtbl = &D3DXMesh_Vtbl;
1042 object->ref = 1;
1044 object->numfaces = numfaces;
1045 object->numvertices = numvertices;
1046 object->options = options;
1047 object->fvf = fvf;
1048 object->device = device;
1049 IDirect3DDevice9_AddRef(device);
1051 object->vertex_declaration = vertex_declaration;
1052 object->vertex_buffer = vertex_buffer;
1053 object->index_buffer = index_buffer;
1055 *mesh = &object->ID3DXMesh_iface;
1057 return D3D_OK;
1060 /*************************************************************************
1061 * D3DXCreateMeshFVF
1063 HRESULT WINAPI D3DXCreateMeshFVF(DWORD numfaces, DWORD numvertices, DWORD options, DWORD fvf,
1064 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
1066 HRESULT hr;
1067 D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
1069 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces, numvertices, options, fvf, device, mesh);
1071 hr = D3DXDeclaratorFromFVF(fvf, declaration);
1072 if (FAILED(hr)) return hr;
1074 return D3DXCreateMesh(numfaces, numvertices, options, declaration, device, mesh);
1077 HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height,
1078 FLOAT depth, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1080 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device, width, height, depth, mesh, adjacency);
1082 return E_NOTIMPL;
1085 struct vertex
1087 D3DXVECTOR3 position;
1088 D3DXVECTOR3 normal;
1091 typedef WORD face[3];
1093 struct sincos_table
1095 float *sin;
1096 float *cos;
1099 static void free_sincos_table(struct sincos_table *sincos_table)
1101 HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1102 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1105 /* pre compute sine and cosine tables; caller must free */
1106 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1108 float angle;
1109 int i;
1111 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1112 if (!sincos_table->sin)
1114 return FALSE;
1116 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1117 if (!sincos_table->cos)
1119 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1120 return FALSE;
1123 angle = angle_start;
1124 for (i = 0; i < n; i++)
1126 sincos_table->sin[i] = sin(angle);
1127 sincos_table->cos[i] = cos(angle);
1128 angle += angle_step;
1131 return TRUE;
1134 static WORD vertex_index(UINT slices, int slice, int stack)
1136 return stack*slices+slice+1;
1139 HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices,
1140 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1142 DWORD number_of_vertices, number_of_faces;
1143 HRESULT hr;
1144 ID3DXMesh *sphere;
1145 struct vertex *vertices;
1146 face *faces;
1147 float phi_step, phi_start;
1148 struct sincos_table phi;
1149 float theta_step, theta, sin_theta, cos_theta;
1150 DWORD vertex, face;
1151 int slice, stack;
1153 TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency);
1155 if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh)
1157 return D3DERR_INVALIDCALL;
1160 if (adjacency)
1162 FIXME("Case of adjacency != NULL not implemented.\n");
1163 return E_NOTIMPL;
1166 number_of_vertices = 2 + slices * (stacks-1);
1167 number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1169 hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1170 D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere);
1171 if (FAILED(hr))
1173 return hr;
1176 hr = sphere->lpVtbl->LockVertexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1177 if (FAILED(hr))
1179 sphere->lpVtbl->Release(sphere);
1180 return hr;
1183 hr = sphere->lpVtbl->LockIndexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&faces);
1184 if (FAILED(hr))
1186 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1187 sphere->lpVtbl->Release(sphere);
1188 return hr;
1191 /* phi = angle on xz plane wrt z axis */
1192 phi_step = -2 * M_PI / slices;
1193 phi_start = M_PI / 2;
1195 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1197 sphere->lpVtbl->UnlockIndexBuffer(sphere);
1198 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1199 sphere->lpVtbl->Release(sphere);
1200 return E_OUTOFMEMORY;
1203 /* theta = angle on xy plane wrt x axis */
1204 theta_step = M_PI / stacks;
1205 theta = theta_step;
1207 vertex = 0;
1208 face = 0;
1209 stack = 0;
1211 vertices[vertex].normal.x = 0.0f;
1212 vertices[vertex].normal.y = 0.0f;
1213 vertices[vertex].normal.z = 1.0f;
1214 vertices[vertex].position.x = 0.0f;
1215 vertices[vertex].position.y = 0.0f;
1216 vertices[vertex].position.z = radius;
1217 vertex++;
1219 for (stack = 0; stack < stacks - 1; stack++)
1221 sin_theta = sin(theta);
1222 cos_theta = cos(theta);
1224 for (slice = 0; slice < slices; slice++)
1226 vertices[vertex].normal.x = sin_theta * phi.cos[slice];
1227 vertices[vertex].normal.y = sin_theta * phi.sin[slice];
1228 vertices[vertex].normal.z = cos_theta;
1229 vertices[vertex].position.x = radius * sin_theta * phi.cos[slice];
1230 vertices[vertex].position.y = radius * sin_theta * phi.sin[slice];
1231 vertices[vertex].position.z = radius * cos_theta;
1232 vertex++;
1234 if (slice > 0)
1236 if (stack == 0)
1238 /* top stack is triangle fan */
1239 faces[face][0] = 0;
1240 faces[face][1] = slice + 1;
1241 faces[face][2] = slice;
1242 face++;
1244 else
1246 /* stacks in between top and bottom are quad strips */
1247 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1248 faces[face][1] = vertex_index(slices, slice, stack-1);
1249 faces[face][2] = vertex_index(slices, slice-1, stack);
1250 face++;
1252 faces[face][0] = vertex_index(slices, slice, stack-1);
1253 faces[face][1] = vertex_index(slices, slice, stack);
1254 faces[face][2] = vertex_index(slices, slice-1, stack);
1255 face++;
1260 theta += theta_step;
1262 if (stack == 0)
1264 faces[face][0] = 0;
1265 faces[face][1] = 1;
1266 faces[face][2] = slice;
1267 face++;
1269 else
1271 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1272 faces[face][1] = vertex_index(slices, 0, stack-1);
1273 faces[face][2] = vertex_index(slices, slice-1, stack);
1274 face++;
1276 faces[face][0] = vertex_index(slices, 0, stack-1);
1277 faces[face][1] = vertex_index(slices, 0, stack);
1278 faces[face][2] = vertex_index(slices, slice-1, stack);
1279 face++;
1283 vertices[vertex].position.x = 0.0f;
1284 vertices[vertex].position.y = 0.0f;
1285 vertices[vertex].position.z = -radius;
1286 vertices[vertex].normal.x = 0.0f;
1287 vertices[vertex].normal.y = 0.0f;
1288 vertices[vertex].normal.z = -1.0f;
1290 /* bottom stack is triangle fan */
1291 for (slice = 1; slice < slices; slice++)
1293 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1294 faces[face][1] = vertex_index(slices, slice, stack-1);
1295 faces[face][2] = vertex;
1296 face++;
1299 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1300 faces[face][1] = vertex_index(slices, 0, stack-1);
1301 faces[face][2] = vertex;
1303 free_sincos_table(&phi);
1304 sphere->lpVtbl->UnlockIndexBuffer(sphere);
1305 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1306 *mesh = sphere;
1308 return D3D_OK;
1311 HRESULT WINAPI D3DXCreateCylinder(LPDIRECT3DDEVICE9 device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices,
1312 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1314 DWORD number_of_vertices, number_of_faces;
1315 HRESULT hr;
1316 ID3DXMesh *cylinder;
1317 struct vertex *vertices;
1318 face *faces;
1319 float theta_step, theta_start;
1320 struct sincos_table theta;
1321 float delta_radius, radius, radius_step;
1322 float z, z_step, z_normal;
1323 DWORD vertex, face;
1324 int slice, stack;
1326 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device, radius1, radius2, length, slices, stacks, mesh, adjacency);
1328 if (device == NULL || radius1 < 0.0f || radius2 < 0.0f || length < 0.0f || slices < 2 || stacks < 1 || mesh == NULL)
1330 return D3DERR_INVALIDCALL;
1333 if (adjacency)
1335 FIXME("Case of adjacency != NULL not implemented.\n");
1336 return E_NOTIMPL;
1339 number_of_vertices = 2 + (slices * (3 + stacks));
1340 number_of_faces = 2 * slices + stacks * (2 * slices);
1342 hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1343 D3DFVF_XYZ | D3DFVF_NORMAL, device, &cylinder);
1344 if (FAILED(hr))
1346 return hr;
1349 hr = cylinder->lpVtbl->LockVertexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1350 if (FAILED(hr))
1352 cylinder->lpVtbl->Release(cylinder);
1353 return hr;
1356 hr = cylinder->lpVtbl->LockIndexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&faces);
1357 if (FAILED(hr))
1359 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1360 cylinder->lpVtbl->Release(cylinder);
1361 return hr;
1364 /* theta = angle on xy plane wrt x axis */
1365 theta_step = -2 * M_PI / slices;
1366 theta_start = M_PI / 2;
1368 if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1370 cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1371 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1372 cylinder->lpVtbl->Release(cylinder);
1373 return E_OUTOFMEMORY;
1376 vertex = 0;
1377 face = 0;
1378 stack = 0;
1380 delta_radius = radius1 - radius2;
1381 radius = radius1;
1382 radius_step = delta_radius / stacks;
1384 z = -length / 2;
1385 z_step = length / stacks;
1386 z_normal = delta_radius / length;
1387 if (isnan(z_normal))
1389 z_normal = 0.0f;
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;
1408 if (slice > 0)
1410 faces[face][0] = 0;
1411 faces[face][1] = slice;
1412 faces[face++][2] = slice + 1;
1416 faces[face][0] = 0;
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);
1444 if (stack > 1)
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)
1457 z += z_step;
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;
1471 if (slice > 0)
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);
1493 *mesh = cylinder;
1495 return D3D_OK;
1498 HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER* adjacency)
1500 FIXME("(%p, %p, %p): stub\n", device, mesh, adjacency);
1502 return E_NOTIMPL;