wined3d: Use surface_blt_to_drawable() in IWineD3DSurfaceImpl_BltOverride().
[wine/multimedia.git] / dlls / d3dx9_36 / mesh.c
blobbbcbf138445873db238e6126ff924dd0453a4a99
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 /*** IUnknown methods ***/
37 static HRESULT WINAPI ID3DXMeshImpl_QueryInterface(ID3DXMesh *iface, REFIID riid, LPVOID *object)
39 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
41 TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), object);
43 if (IsEqualGUID(riid, &IID_IUnknown) ||
44 IsEqualGUID(riid, &IID_ID3DXBaseMesh) ||
45 IsEqualGUID(riid, &IID_ID3DXMesh))
47 iface->lpVtbl->AddRef(iface);
48 *object = This;
49 return S_OK;
52 WARN("Interface %s not found.\n", debugstr_guid(riid));
54 return E_NOINTERFACE;
57 static ULONG WINAPI ID3DXMeshImpl_AddRef(ID3DXMesh *iface)
59 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
61 TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
63 return InterlockedIncrement(&This->ref);
66 static ULONG WINAPI ID3DXMeshImpl_Release(ID3DXMesh *iface)
68 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
69 ULONG ref = InterlockedDecrement(&This->ref);
71 TRACE("(%p)->(): Release from %d\n", This, ref + 1);
73 if (!ref)
75 IDirect3DIndexBuffer9_Release(This->index_buffer);
76 IDirect3DVertexBuffer9_Release(This->vertex_buffer);
77 IDirect3DVertexDeclaration9_Release(This->vertex_declaration);
78 IDirect3DDevice9_Release(This->device);
79 HeapFree(GetProcessHeap(), 0, This);
82 return ref;
85 /*** ID3DXBaseMesh ***/
86 static HRESULT WINAPI ID3DXMeshImpl_DrawSubset(ID3DXMesh *iface, DWORD attrib_id)
88 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
90 FIXME("(%p)->(%u): stub\n", This, attrib_id);
92 return E_NOTIMPL;
95 static DWORD WINAPI ID3DXMeshImpl_GetNumFaces(ID3DXMesh *iface)
97 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
99 TRACE("(%p)\n", This);
101 return This->numfaces;
104 static DWORD WINAPI ID3DXMeshImpl_GetNumVertices(ID3DXMesh *iface)
106 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
108 TRACE("(%p)\n", This);
110 return This->numvertices;
113 static DWORD WINAPI ID3DXMeshImpl_GetFVF(ID3DXMesh *iface)
115 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
117 TRACE("(%p)\n", This);
119 return This->fvf;
122 static HRESULT WINAPI ID3DXMeshImpl_GetDeclaration(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
124 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
125 UINT numelements;
127 TRACE("(%p)\n", This);
129 if (declaration == NULL) return D3DERR_INVALIDCALL;
131 return IDirect3DVertexDeclaration9_GetDeclaration(This->vertex_declaration,
132 declaration,
133 &numelements);
136 static DWORD WINAPI ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh *iface)
138 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
140 FIXME("(%p): stub\n", This);
142 return 0; /* arbitrary since we cannot return E_NOTIMPL */
145 static DWORD WINAPI ID3DXMeshImpl_GetOptions(ID3DXMesh *iface)
147 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
149 TRACE("(%p)\n", This);
151 return This->options;
154 static HRESULT WINAPI ID3DXMeshImpl_GetDevice(ID3DXMesh *iface, LPDIRECT3DDEVICE9 *device)
156 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
158 TRACE("(%p)->(%p)\n", This, device);
160 if (device == NULL) return D3DERR_INVALIDCALL;
161 *device = This->device;
162 IDirect3DDevice9_AddRef(This->device);
164 return D3D_OK;
167 static HRESULT WINAPI ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh *iface, DWORD options, DWORD fvf, LPDIRECT3DDEVICE9 device, LPD3DXMESH *clone_mesh)
169 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
171 FIXME("(%p)->(%u,%u,%p,%p): stub\n", This, options, fvf, device, clone_mesh);
173 return E_NOTIMPL;
176 static HRESULT WINAPI ID3DXMeshImpl_CloneMesh(ID3DXMesh *iface, DWORD options, CONST D3DVERTEXELEMENT9 *declaration, LPDIRECT3DDEVICE9 device,
177 LPD3DXMESH *clone_mesh)
179 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
181 FIXME("(%p)->(%u,%p,%p,%p): stub\n", This, options, declaration, device, clone_mesh);
183 return E_NOTIMPL;
186 static HRESULT WINAPI ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh *iface, LPDIRECT3DVERTEXBUFFER9 *vertex_buffer)
188 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
190 TRACE("(%p)->(%p)\n", This, vertex_buffer);
192 if (vertex_buffer == NULL) return D3DERR_INVALIDCALL;
193 *vertex_buffer = This->vertex_buffer;
194 IDirect3DVertexBuffer9_AddRef(This->vertex_buffer);
196 return D3D_OK;
199 static HRESULT WINAPI ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh *iface, LPDIRECT3DINDEXBUFFER9 *index_buffer)
201 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
203 TRACE("(%p)->(%p)\n", This, index_buffer);
205 if (index_buffer == NULL) return D3DERR_INVALIDCALL;
206 *index_buffer = This->index_buffer;
207 IDirect3DIndexBuffer9_AddRef(This->index_buffer);
209 return D3D_OK;
212 static HRESULT WINAPI ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
214 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
216 TRACE("(%p)->(%u,%p)\n", This, flags, data);
218 return IDirect3DVertexBuffer9_Lock(This->vertex_buffer, 0, 0, data, flags);
221 static HRESULT WINAPI ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh *iface)
223 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
225 TRACE("(%p)\n", This);
227 return IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
230 static HRESULT WINAPI ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
232 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
234 TRACE("(%p)->(%u,%p)\n", This, flags, data);
236 return IDirect3DIndexBuffer9_Lock(This->index_buffer, 0, 0, data, flags);
239 static HRESULT WINAPI ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh *iface)
241 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
243 TRACE("(%p)\n", This);
245 return IDirect3DIndexBuffer9_Unlock(This->index_buffer);
248 static HRESULT WINAPI ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTRIBUTERANGE *attrib_table, DWORD *attrib_table_size)
250 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
252 FIXME("(%p)->(%p,%p): stub\n", This, attrib_table, attrib_table_size);
254 return E_NOTIMPL;
257 static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency)
259 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
261 FIXME("(%p)->(%p,%p): stub\n", This, point_reps, adjacency);
263 return E_NOTIMPL;
266 static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, CONST DWORD *adjacency, DWORD *point_reps)
268 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
270 FIXME("(%p)->(%p,%p): stub\n", This, adjacency, point_reps);
272 return E_NOTIMPL;
275 static HRESULT WINAPI ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh *iface, FLOAT epsilon, DWORD *adjacency)
277 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
279 FIXME("(%p)->(%f,%p): stub\n", This, epsilon, adjacency);
281 return E_NOTIMPL;
284 static HRESULT WINAPI ID3DXMeshImpl_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
286 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
288 FIXME("(%p)->(%p): stub\n", This, declaration);
290 return E_NOTIMPL;
293 /*** ID3DXMesh ***/
294 static HRESULT WINAPI ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh *iface, DWORD flags, DWORD **data)
296 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
298 FIXME("(%p)->(%u,%p): stub\n", This, flags, data);
300 return E_NOTIMPL;
303 static HRESULT WINAPI ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh *iface)
305 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
307 FIXME("(%p): stub\n", This);
309 return E_NOTIMPL;
312 static HRESULT WINAPI ID3DXMeshImpl_Optimize(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
313 DWORD *face_remap, LPD3DXBUFFER *vertex_remap, LPD3DXMESH *opt_mesh)
315 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
317 FIXME("(%p)->(%u,%p,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap, opt_mesh);
319 return E_NOTIMPL;
322 static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
323 DWORD *face_remap, LPD3DXBUFFER *vertex_remap)
325 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
327 FIXME("(%p)->(%u,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap);
329 return E_NOTIMPL;
332 static HRESULT WINAPI ID3DXMeshImpl_SetAttributeTable(ID3DXMesh *iface, CONST D3DXATTRIBUTERANGE *attrib_table, DWORD attrib_table_size)
334 ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
336 FIXME("(%p)->(%p,%u): stub\n", This, attrib_table, attrib_table_size);
338 return E_NOTIMPL;
341 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl =
343 /*** IUnknown methods ***/
344 ID3DXMeshImpl_QueryInterface,
345 ID3DXMeshImpl_AddRef,
346 ID3DXMeshImpl_Release,
347 /*** ID3DXBaseMesh ***/
348 ID3DXMeshImpl_DrawSubset,
349 ID3DXMeshImpl_GetNumFaces,
350 ID3DXMeshImpl_GetNumVertices,
351 ID3DXMeshImpl_GetFVF,
352 ID3DXMeshImpl_GetDeclaration,
353 ID3DXMeshImpl_GetNumBytesPerVertex,
354 ID3DXMeshImpl_GetOptions,
355 ID3DXMeshImpl_GetDevice,
356 ID3DXMeshImpl_CloneMeshFVF,
357 ID3DXMeshImpl_CloneMesh,
358 ID3DXMeshImpl_GetVertexBuffer,
359 ID3DXMeshImpl_GetIndexBuffer,
360 ID3DXMeshImpl_LockVertexBuffer,
361 ID3DXMeshImpl_UnlockVertexBuffer,
362 ID3DXMeshImpl_LockIndexBuffer,
363 ID3DXMeshImpl_UnlockIndexBuffer,
364 ID3DXMeshImpl_GetAttributeTable,
365 ID3DXMeshImpl_ConvertPointRepsToAdjacency,
366 ID3DXMeshImpl_ConvertAdjacencyToPointReps,
367 ID3DXMeshImpl_GenerateAdjacency,
368 ID3DXMeshImpl_UpdateSemantics,
369 /*** ID3DXMesh ***/
370 ID3DXMeshImpl_LockAttributeBuffer,
371 ID3DXMeshImpl_UnlockAttributeBuffer,
372 ID3DXMeshImpl_Optimize,
373 ID3DXMeshImpl_OptimizeInplace,
374 ID3DXMeshImpl_SetAttributeTable
377 /*************************************************************************
378 * D3DXBoxBoundProbe
380 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
382 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
383 Amy Williams University of Utah
384 Steve Barrus University of Utah
385 R. Keith Morley University of Utah
386 Peter Shirley University of Utah
388 International Conference on Computer Graphics and Interactive Techniques archive
389 ACM SIGGRAPH 2005 Courses
390 Los Angeles, California
392 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
394 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
395 against each slab, if there's anything left of the ray after we're
396 done we've got an intersection of the ray with the box.
400 FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
402 div = 1.0f / praydirection->x;
403 if ( div >= 0.0f )
405 tmin = ( pmin->x - prayposition->x ) * div;
406 tmax = ( pmax->x - prayposition->x ) * div;
408 else
410 tmin = ( pmax->x - prayposition->x ) * div;
411 tmax = ( pmin->x - prayposition->x ) * div;
414 if ( tmax < 0.0f ) return FALSE;
416 div = 1.0f / praydirection->y;
417 if ( div >= 0.0f )
419 tymin = ( pmin->y - prayposition->y ) * div;
420 tymax = ( pmax->y - prayposition->y ) * div;
422 else
424 tymin = ( pmax->y - prayposition->y ) * div;
425 tymax = ( pmin->y - prayposition->y ) * div;
428 if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
430 if ( tymin > tmin ) tmin = tymin;
431 if ( tymax < tmax ) tmax = tymax;
433 div = 1.0f / praydirection->z;
434 if ( div >= 0.0f )
436 tzmin = ( pmin->z - prayposition->z ) * div;
437 tzmax = ( pmax->z - prayposition->z ) * div;
439 else
441 tzmin = ( pmax->z - prayposition->z ) * div;
442 tzmax = ( pmin->z - prayposition->z ) * div;
445 if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
447 return TRUE;
450 /*************************************************************************
451 * D3DXComputeBoundingBox
453 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
455 D3DXVECTOR3 vec;
456 unsigned int i;
458 if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
460 *pmin = *pfirstposition;
461 *pmax = *pmin;
463 for(i=0; i<numvertices; i++)
465 vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
467 if ( vec.x < pmin->x ) pmin->x = vec.x;
468 if ( vec.x > pmax->x ) pmax->x = vec.x;
470 if ( vec.y < pmin->y ) pmin->y = vec.y;
471 if ( vec.y > pmax->y ) pmax->y = vec.y;
473 if ( vec.z < pmin->z ) pmin->z = vec.z;
474 if ( vec.z > pmax->z ) pmax->z = vec.z;
477 return D3D_OK;
480 /*************************************************************************
481 * D3DXComputeBoundingSphere
483 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
485 D3DXVECTOR3 temp, temp1;
486 FLOAT d;
487 unsigned int i;
489 if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
491 temp.x = 0.0f;
492 temp.y = 0.0f;
493 temp.z = 0.0f;
494 temp1 = temp;
495 d = 0.0f;
496 *pradius = 0.0f;
498 for(i=0; i<numvertices; i++)
500 D3DXVec3Add(&temp1, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
501 temp = temp1;
504 D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
506 for(i=0; i<numvertices; i++)
508 d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
509 if ( d > *pradius ) *pradius = d;
511 return D3D_OK;
514 static const UINT d3dx_decltype_size[D3DDECLTYPE_UNUSED] =
516 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
517 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
518 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
519 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
520 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
521 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
522 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
523 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
524 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
525 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
526 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
527 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
528 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
529 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
530 /* D3DDECLTYPE_DEC3N */ 4,
531 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
532 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
535 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
536 D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
538 declaration[*idx].Stream = 0;
539 declaration[*idx].Offset = *offset;
540 declaration[*idx].Type = type;
541 declaration[*idx].Method = D3DDECLMETHOD_DEFAULT;
542 declaration[*idx].Usage = usage;
543 declaration[*idx].UsageIndex = usage_idx;
545 *offset += d3dx_decltype_size[type];
546 ++(*idx);
549 /*************************************************************************
550 * D3DXDeclaratorFromFVF
552 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
554 static const D3DVERTEXELEMENT9 end_element = D3DDECL_END();
555 DWORD tex_count = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
556 unsigned int offset = 0;
557 unsigned int idx = 0;
558 unsigned int i;
560 TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
562 if (fvf & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) return D3DERR_INVALIDCALL;
564 if (fvf & D3DFVF_POSITION_MASK)
566 BOOL has_blend = (fvf & D3DFVF_XYZB5) >= D3DFVF_XYZB1;
567 DWORD blend_count = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
568 BOOL has_blend_idx = (fvf & D3DFVF_LASTBETA_D3DCOLOR) || (fvf & D3DFVF_LASTBETA_UBYTE4);
570 if (has_blend_idx) --blend_count;
572 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
573 || (has_blend && blend_count > 4))
574 return D3DERR_INVALIDCALL;
576 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
577 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_POSITIONT, 0);
578 else
579 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_POSITION, 0);
581 if (has_blend)
583 switch (blend_count)
585 case 0:
586 break;
587 case 1:
588 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_BLENDWEIGHT, 0);
589 break;
590 case 2:
591 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_BLENDWEIGHT, 0);
592 break;
593 case 3:
594 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_BLENDWEIGHT, 0);
595 break;
596 case 4:
597 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_BLENDWEIGHT, 0);
598 break;
599 default:
600 ERR("Invalid blend count %u.\n", blend_count);
601 break;
604 if (has_blend_idx)
606 if (fvf & D3DFVF_LASTBETA_UBYTE4)
607 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_UBYTE4, D3DDECLUSAGE_BLENDINDICES, 0);
608 else if (fvf & D3DFVF_LASTBETA_D3DCOLOR)
609 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_BLENDINDICES, 0);
614 if (fvf & D3DFVF_NORMAL)
615 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_NORMAL, 0);
616 if (fvf & D3DFVF_PSIZE)
617 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_PSIZE, 0);
618 if (fvf & D3DFVF_DIFFUSE)
619 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 0);
620 if (fvf & D3DFVF_SPECULAR)
621 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 1);
623 for (i = 0; i < tex_count; ++i)
625 switch ((fvf >> (16 + 2 * i)) & 0x03)
627 case D3DFVF_TEXTUREFORMAT1:
628 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_TEXCOORD, i);
629 break;
630 case D3DFVF_TEXTUREFORMAT2:
631 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_TEXCOORD, i);
632 break;
633 case D3DFVF_TEXTUREFORMAT3:
634 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_TEXCOORD, i);
635 break;
636 case D3DFVF_TEXTUREFORMAT4:
637 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_TEXCOORD, i);
638 break;
642 declaration[idx] = end_element;
644 return D3D_OK;
647 /*************************************************************************
648 * D3DXFVFFromDeclarator
650 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
652 unsigned int i = 0, texture, offset;
654 TRACE("(%p, %p)\n", declaration, fvf);
656 *fvf = 0;
657 if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
659 if ((declaration[1].Type == D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
660 declaration[1].UsageIndex == 0) &&
661 (declaration[2].Type == D3DDECLTYPE_FLOAT1 && declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES &&
662 declaration[2].UsageIndex == 0))
664 return D3DERR_INVALIDCALL;
666 else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
667 declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
669 if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
671 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
673 else
675 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
677 i = 2;
679 else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
680 declaration[1].UsageIndex == 0)
682 if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
683 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
685 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
687 *fvf |= D3DFVF_LASTBETA_UBYTE4;
689 else
691 *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
693 switch (declaration[1].Type)
695 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB2; break;
696 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB3; break;
697 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB4; break;
698 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB5; break;
700 i = 3;
702 else
704 switch (declaration[1].Type)
706 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB1; break;
707 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB2; break;
708 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB3; break;
709 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB4; break;
711 i = 2;
714 else
716 *fvf |= D3DFVF_XYZ;
717 i = 1;
720 else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
721 declaration[0].UsageIndex == 0)
723 *fvf |= D3DFVF_XYZRHW;
724 i = 1;
727 if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
729 *fvf |= D3DFVF_NORMAL;
730 i++;
732 if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
733 declaration[i].UsageIndex == 0)
735 *fvf |= D3DFVF_PSIZE;
736 i++;
738 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
739 declaration[i].UsageIndex == 0)
741 *fvf |= D3DFVF_DIFFUSE;
742 i++;
744 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
745 declaration[i].UsageIndex == 1)
747 *fvf |= D3DFVF_SPECULAR;
748 i++;
751 for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
753 if (declaration[i].Stream == 0xFF)
755 break;
757 else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
758 declaration[i].UsageIndex == texture)
760 *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
762 else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
763 declaration[i].UsageIndex == texture)
765 *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
767 else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
768 declaration[i].UsageIndex == texture)
770 *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
772 else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
773 declaration[i].UsageIndex == texture)
775 *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
777 else
779 return D3DERR_INVALIDCALL;
783 *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
785 for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
786 offset += d3dx_decltype_size[declaration[i].Type], i++)
788 if (declaration[i].Offset != offset)
790 return D3DERR_INVALIDCALL;
794 return D3D_OK;
797 /*************************************************************************
798 * D3DXGetFVFVertexSize
800 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
802 return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
805 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
807 DWORD size = 0;
808 UINT i;
809 UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
811 if (FVF & D3DFVF_NORMAL) size += sizeof(D3DXVECTOR3);
812 if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
813 if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
814 if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
816 switch (FVF & D3DFVF_POSITION_MASK)
818 case D3DFVF_XYZ: size += sizeof(D3DXVECTOR3); break;
819 case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
820 case D3DFVF_XYZB1: size += 4 * sizeof(FLOAT); break;
821 case D3DFVF_XYZB2: size += 5 * sizeof(FLOAT); break;
822 case D3DFVF_XYZB3: size += 6 * sizeof(FLOAT); break;
823 case D3DFVF_XYZB4: size += 7 * sizeof(FLOAT); break;
824 case D3DFVF_XYZB5: size += 8 * sizeof(FLOAT); break;
825 case D3DFVF_XYZW: size += 4 * sizeof(FLOAT); break;
828 for (i = 0; i < numTextures; i++)
830 size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
833 return size;
836 /*************************************************************************
837 * D3DXGetDeclVertexSize
839 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
841 const D3DVERTEXELEMENT9 *element;
842 UINT size = 0;
844 TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
846 if (!decl) return 0;
848 for (element = decl; element->Stream != 0xff; ++element)
850 UINT type_size;
852 if (element->Stream != stream_idx) continue;
854 if (element->Type >= sizeof(d3dx_decltype_size) / sizeof(*d3dx_decltype_size))
856 FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
857 continue;
860 type_size = d3dx_decltype_size[element->Type];
861 if (element->Offset + type_size > size) size = element->Offset + type_size;
864 return size;
867 /*************************************************************************
868 * D3DXGetDeclLength
870 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
872 const D3DVERTEXELEMENT9 *element;
874 TRACE("decl %p\n", decl);
876 /* null decl results in exception on Windows XP */
878 for (element = decl; element->Stream != 0xff; ++element);
880 return element - decl;
883 /*************************************************************************
884 * D3DXIntersectTri
886 BOOL WINAPI D3DXIntersectTri(CONST D3DXVECTOR3 *p0, CONST D3DXVECTOR3 *p1, CONST D3DXVECTOR3 *p2, CONST D3DXVECTOR3 *praypos, CONST D3DXVECTOR3 *praydir, FLOAT *pu, FLOAT *pv, FLOAT *pdist)
888 D3DXMATRIX m;
889 D3DXVECTOR4 vec;
891 m.u.m[0][0] = p1->x - p0->x;
892 m.u.m[1][0] = p2->x - p0->x;
893 m.u.m[2][0] = -praydir->x;
894 m.u.m[3][0] = 0.0f;
895 m.u.m[0][1] = p1->y - p0->z;
896 m.u.m[1][1] = p2->y - p0->z;
897 m.u.m[2][1] = -praydir->y;
898 m.u.m[3][1] = 0.0f;
899 m.u.m[0][2] = p1->z - p0->z;
900 m.u.m[1][2] = p2->z - p0->z;
901 m.u.m[2][2] = -praydir->z;
902 m.u.m[3][2] = 0.0f;
903 m.u.m[0][3] = 0.0f;
904 m.u.m[1][3] = 0.0f;
905 m.u.m[2][3] = 0.0f;
906 m.u.m[3][3] = 1.0f;
908 vec.x = praypos->x - p0->x;
909 vec.y = praypos->y - p0->y;
910 vec.z = praypos->z - p0->z;
911 vec.w = 0.0f;
913 if ( D3DXMatrixInverse(&m, NULL, &m) )
915 D3DXVec4Transform(&vec, &vec, &m);
916 if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
918 *pu = vec.x;
919 *pv = vec.y;
920 *pdist = fabs( vec.z );
921 return TRUE;
925 return FALSE;
928 /*************************************************************************
929 * D3DXSphereBoundProbe
931 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
933 D3DXVECTOR3 difference;
934 FLOAT a, b, c, d;
936 a = D3DXVec3LengthSq(praydirection);
937 if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
938 b = D3DXVec3Dot(&difference, praydirection);
939 c = D3DXVec3LengthSq(&difference) - radius * radius;
940 d = b * b - a * c;
942 if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
943 return TRUE;
946 /*************************************************************************
947 * D3DXCreateMesh
949 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options, CONST D3DVERTEXELEMENT9 *declaration,
950 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
952 HRESULT hr;
953 DWORD fvf;
954 IDirect3DVertexDeclaration9 *vertex_declaration;
955 IDirect3DVertexBuffer9 *vertex_buffer;
956 IDirect3DIndexBuffer9 *index_buffer;
957 ID3DXMeshImpl *object;
959 TRACE("(%d, %d, %d, %p, %p, %p)\n", numfaces, numvertices, options, declaration, device, mesh);
961 if (numfaces == 0 || numvertices == 0 || declaration == NULL || device == NULL || mesh == NULL)
963 return D3DERR_INVALIDCALL;
966 hr = D3DXFVFFromDeclarator(declaration, &fvf);
967 if (hr != D3D_OK)
969 fvf = 0;
972 /* Create vertex declaration */
973 hr = IDirect3DDevice9_CreateVertexDeclaration(device,
974 declaration,
975 &vertex_declaration);
976 if (FAILED(hr))
978 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
979 return hr;
982 /* Create vertex buffer */
983 hr = IDirect3DDevice9_CreateVertexBuffer(device,
984 numvertices * D3DXGetDeclVertexSize(declaration, declaration[0].Stream),
986 fvf,
987 D3DPOOL_MANAGED,
988 &vertex_buffer,
989 NULL);
990 if (FAILED(hr))
992 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
993 IDirect3DVertexDeclaration9_Release(vertex_declaration);
994 return hr;
997 /* Create index buffer */
998 hr = IDirect3DDevice9_CreateIndexBuffer(device,
999 numfaces * 6, /* 3 vertices per triangle, 2 triangles per face */
1001 D3DFMT_INDEX16,
1002 D3DPOOL_MANAGED,
1003 &index_buffer,
1004 NULL);
1005 if (FAILED(hr))
1007 WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1008 IDirect3DVertexBuffer9_Release(vertex_buffer);
1009 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1010 return hr;
1013 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXMeshImpl));
1014 if (object == NULL)
1016 IDirect3DIndexBuffer9_Release(index_buffer);
1017 IDirect3DVertexBuffer9_Release(vertex_buffer);
1018 IDirect3DVertexDeclaration9_Release(vertex_declaration);
1019 *mesh = NULL;
1020 return E_OUTOFMEMORY;
1022 object->lpVtbl = &D3DXMesh_Vtbl;
1023 object->ref = 1;
1025 object->numfaces = numfaces;
1026 object->numvertices = numvertices;
1027 object->options = options;
1028 object->fvf = fvf;
1029 object->device = device;
1030 IDirect3DDevice9_AddRef(device);
1032 object->vertex_declaration = vertex_declaration;
1033 object->vertex_buffer = vertex_buffer;
1034 object->index_buffer = index_buffer;
1036 *mesh = (ID3DXMesh*)object;
1038 return D3D_OK;
1041 /*************************************************************************
1042 * D3DXCreateMeshFVF
1044 HRESULT WINAPI D3DXCreateMeshFVF(DWORD numfaces, DWORD numvertices, DWORD options, DWORD fvf,
1045 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
1047 HRESULT hr;
1048 D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
1050 TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces, numvertices, options, fvf, device, mesh);
1052 hr = D3DXDeclaratorFromFVF(fvf, declaration);
1053 if (FAILED(hr)) return hr;
1055 return D3DXCreateMesh(numfaces, numvertices, options, declaration, device, mesh);
1058 HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height,
1059 FLOAT depth, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1061 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device, width, height, depth, mesh, adjacency);
1063 return E_NOTIMPL;
1066 struct vertex
1068 D3DXVECTOR3 position;
1069 D3DXVECTOR3 normal;
1072 typedef WORD face[3];
1074 struct sincos_table
1076 float *sin;
1077 float *cos;
1080 static void free_sincos_table(struct sincos_table *sincos_table)
1082 HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1083 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1086 /* pre compute sine and cosine tables; caller must free */
1087 static BOOL compute_sincos_table(struct sincos_table *sincos_table, float angle_start, float angle_step, int n)
1089 float angle;
1090 int i;
1092 sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1093 if (!sincos_table->sin)
1095 return FALSE;
1097 sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1098 if (!sincos_table->cos)
1100 HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1101 return FALSE;
1104 angle = angle_start;
1105 for (i = 0; i < n; i++)
1107 sincos_table->sin[i] = sin(angle);
1108 sincos_table->cos[i] = cos(angle);
1109 angle += angle_step;
1112 return TRUE;
1115 static WORD vertex_index(UINT slices, int slice, int stack)
1117 return stack*slices+slice+1;
1120 HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices,
1121 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1123 DWORD number_of_vertices, number_of_faces;
1124 HRESULT hr;
1125 ID3DXMesh *sphere;
1126 struct vertex *vertices;
1127 face *faces;
1128 float phi_step, phi_start;
1129 struct sincos_table phi;
1130 float theta_step, theta, sin_theta, cos_theta;
1131 DWORD vertex, face;
1132 int slice, stack;
1134 TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency);
1136 if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh)
1138 return D3DERR_INVALIDCALL;
1141 if (adjacency)
1143 FIXME("Case of adjacency != NULL not implemented.\n");
1144 return E_NOTIMPL;
1147 number_of_vertices = 2 + slices * (stacks-1);
1148 number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1150 hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1151 D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere);
1152 if (FAILED(hr))
1154 return hr;
1157 hr = sphere->lpVtbl->LockVertexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1158 if (FAILED(hr))
1160 sphere->lpVtbl->Release(sphere);
1161 return hr;
1164 hr = sphere->lpVtbl->LockIndexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&faces);
1165 if (FAILED(hr))
1167 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1168 sphere->lpVtbl->Release(sphere);
1169 return hr;
1172 /* phi = angle on xz plane wrt z axis */
1173 phi_step = -2 * M_PI / slices;
1174 phi_start = M_PI / 2;
1176 if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1178 sphere->lpVtbl->UnlockIndexBuffer(sphere);
1179 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1180 sphere->lpVtbl->Release(sphere);
1181 return E_OUTOFMEMORY;
1184 /* theta = angle on xy plane wrt x axis */
1185 theta_step = M_PI / stacks;
1186 theta = theta_step;
1188 vertex = 0;
1189 face = 0;
1190 stack = 0;
1192 vertices[vertex].normal.x = 0.0f;
1193 vertices[vertex].normal.y = 0.0f;
1194 vertices[vertex].normal.z = 1.0f;
1195 vertices[vertex].position.x = 0.0f;
1196 vertices[vertex].position.y = 0.0f;
1197 vertices[vertex].position.z = radius;
1198 vertex++;
1200 for (stack = 0; stack < stacks - 1; stack++)
1202 sin_theta = sin(theta);
1203 cos_theta = cos(theta);
1205 for (slice = 0; slice < slices; slice++)
1207 vertices[vertex].normal.x = sin_theta * phi.cos[slice];
1208 vertices[vertex].normal.y = sin_theta * phi.sin[slice];
1209 vertices[vertex].normal.z = cos_theta;
1210 vertices[vertex].position.x = radius * sin_theta * phi.cos[slice];
1211 vertices[vertex].position.y = radius * sin_theta * phi.sin[slice];
1212 vertices[vertex].position.z = radius * cos_theta;
1213 vertex++;
1215 if (slice > 0)
1217 if (stack == 0)
1219 /* top stack is triangle fan */
1220 faces[face][0] = 0;
1221 faces[face][1] = slice + 1;
1222 faces[face][2] = slice;
1223 face++;
1225 else
1227 /* stacks in between top and bottom are quad strips */
1228 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1229 faces[face][1] = vertex_index(slices, slice, stack-1);
1230 faces[face][2] = vertex_index(slices, slice-1, stack);
1231 face++;
1233 faces[face][0] = vertex_index(slices, slice, stack-1);
1234 faces[face][1] = vertex_index(slices, slice, stack);
1235 faces[face][2] = vertex_index(slices, slice-1, stack);
1236 face++;
1241 theta += theta_step;
1243 if (stack == 0)
1245 faces[face][0] = 0;
1246 faces[face][1] = 1;
1247 faces[face][2] = slice;
1248 face++;
1250 else
1252 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1253 faces[face][1] = vertex_index(slices, 0, stack-1);
1254 faces[face][2] = vertex_index(slices, slice-1, stack);
1255 face++;
1257 faces[face][0] = vertex_index(slices, 0, stack-1);
1258 faces[face][1] = vertex_index(slices, 0, stack);
1259 faces[face][2] = vertex_index(slices, slice-1, stack);
1260 face++;
1264 vertices[vertex].position.x = 0.0f;
1265 vertices[vertex].position.y = 0.0f;
1266 vertices[vertex].position.z = -radius;
1267 vertices[vertex].normal.x = 0.0f;
1268 vertices[vertex].normal.y = 0.0f;
1269 vertices[vertex].normal.z = -1.0f;
1271 /* bottom stack is triangle fan */
1272 for (slice = 1; slice < slices; slice++)
1274 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1275 faces[face][1] = vertex_index(slices, slice, stack-1);
1276 faces[face][2] = vertex;
1277 face++;
1280 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1281 faces[face][1] = vertex_index(slices, 0, stack-1);
1282 faces[face][2] = vertex;
1284 free_sincos_table(&phi);
1285 sphere->lpVtbl->UnlockIndexBuffer(sphere);
1286 sphere->lpVtbl->UnlockVertexBuffer(sphere);
1287 *mesh = sphere;
1289 return D3D_OK;
1292 HRESULT WINAPI D3DXCreateCylinder(LPDIRECT3DDEVICE9 device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices,
1293 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1295 DWORD number_of_vertices, number_of_faces;
1296 HRESULT hr;
1297 ID3DXMesh *cylinder;
1298 struct vertex *vertices;
1299 face *faces;
1300 float theta_step, theta_start;
1301 struct sincos_table theta;
1302 float delta_radius, radius, radius_step;
1303 float z, z_step, z_normal;
1304 DWORD vertex, face;
1305 int slice, stack;
1307 TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device, radius1, radius2, length, slices, stacks, mesh, adjacency);
1309 if (device == NULL || radius1 < 0.0f || radius2 < 0.0f || length < 0.0f || slices < 2 || stacks < 1 || mesh == NULL)
1311 return D3DERR_INVALIDCALL;
1314 if (adjacency)
1316 FIXME("Case of adjacency != NULL not implemented.\n");
1317 return E_NOTIMPL;
1320 number_of_vertices = 2 + (slices * (3 + stacks));
1321 number_of_faces = 2 * slices + stacks * (2 * slices);
1323 hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1324 D3DFVF_XYZ | D3DFVF_NORMAL, device, &cylinder);
1325 if (FAILED(hr))
1327 return hr;
1330 hr = cylinder->lpVtbl->LockVertexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1331 if (FAILED(hr))
1333 cylinder->lpVtbl->Release(cylinder);
1334 return hr;
1337 hr = cylinder->lpVtbl->LockIndexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&faces);
1338 if (FAILED(hr))
1340 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1341 cylinder->lpVtbl->Release(cylinder);
1342 return hr;
1345 /* theta = angle on xy plane wrt x axis */
1346 theta_step = -2 * M_PI / slices;
1347 theta_start = M_PI / 2;
1349 if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1351 cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1352 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1353 cylinder->lpVtbl->Release(cylinder);
1354 return E_OUTOFMEMORY;
1357 vertex = 0;
1358 face = 0;
1359 stack = 0;
1361 delta_radius = radius1 - radius2;
1362 radius = radius1;
1363 radius_step = delta_radius / stacks;
1365 z = -length / 2;
1366 z_step = length / stacks;
1367 z_normal = delta_radius / length;
1368 if (isnan(z_normal))
1370 z_normal = 0.0f;
1373 vertices[vertex].normal.x = 0.0f;
1374 vertices[vertex].normal.y = 0.0f;
1375 vertices[vertex].normal.z = -1.0f;
1376 vertices[vertex].position.x = 0.0f;
1377 vertices[vertex].position.y = 0.0f;
1378 vertices[vertex++].position.z = z;
1380 for (slice = 0; slice < slices; slice++, vertex++)
1382 vertices[vertex].normal.x = 0.0f;
1383 vertices[vertex].normal.y = 0.0f;
1384 vertices[vertex].normal.z = -1.0f;
1385 vertices[vertex].position.x = radius * theta.cos[slice];
1386 vertices[vertex].position.y = radius * theta.sin[slice];
1387 vertices[vertex].position.z = z;
1389 if (slice > 0)
1391 faces[face][0] = 0;
1392 faces[face][1] = slice;
1393 faces[face++][2] = slice + 1;
1397 faces[face][0] = 0;
1398 faces[face][1] = slice;
1399 faces[face++][2] = 1;
1401 for (stack = 1; stack <= stacks+1; stack++)
1403 for (slice = 0; slice < slices; slice++, vertex++)
1405 vertices[vertex].normal.x = theta.cos[slice];
1406 vertices[vertex].normal.y = theta.sin[slice];
1407 vertices[vertex].normal.z = z_normal;
1408 D3DXVec3Normalize(&vertices[vertex].normal, &vertices[vertex].normal);
1409 vertices[vertex].position.x = radius * theta.cos[slice];
1410 vertices[vertex].position.y = radius * theta.sin[slice];
1411 vertices[vertex].position.z = z;
1413 if (stack > 1 && slice > 0)
1415 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1416 faces[face][1] = vertex_index(slices, slice-1, stack);
1417 faces[face++][2] = vertex_index(slices, slice, stack-1);
1419 faces[face][0] = vertex_index(slices, slice, stack-1);
1420 faces[face][1] = vertex_index(slices, slice-1, stack);
1421 faces[face++][2] = vertex_index(slices, slice, stack);
1425 if (stack > 1)
1427 faces[face][0] = vertex_index(slices, slice-1, stack-1);
1428 faces[face][1] = vertex_index(slices, slice-1, stack);
1429 faces[face++][2] = vertex_index(slices, 0, stack-1);
1431 faces[face][0] = vertex_index(slices, 0, stack-1);
1432 faces[face][1] = vertex_index(slices, slice-1, stack);
1433 faces[face++][2] = vertex_index(slices, 0, stack);
1436 if (stack < stacks + 1)
1438 z += z_step;
1439 radius -= radius_step;
1443 for (slice = 0; slice < slices; slice++, vertex++)
1445 vertices[vertex].normal.x = 0.0f;
1446 vertices[vertex].normal.y = 0.0f;
1447 vertices[vertex].normal.z = 1.0f;
1448 vertices[vertex].position.x = radius * theta.cos[slice];
1449 vertices[vertex].position.y = radius * theta.sin[slice];
1450 vertices[vertex].position.z = z;
1452 if (slice > 0)
1454 faces[face][0] = vertex_index(slices, slice-1, stack);
1455 faces[face][1] = number_of_vertices - 1;
1456 faces[face++][2] = vertex_index(slices, slice, stack);
1460 vertices[vertex].position.x = 0.0f;
1461 vertices[vertex].position.y = 0.0f;
1462 vertices[vertex].position.z = z;
1463 vertices[vertex].normal.x = 0.0f;
1464 vertices[vertex].normal.y = 0.0f;
1465 vertices[vertex].normal.z = 1.0f;
1467 faces[face][0] = vertex_index(slices, slice-1, stack);
1468 faces[face][1] = number_of_vertices - 1;
1469 faces[face][2] = vertex_index(slices, 0, stack);
1471 free_sincos_table(&theta);
1472 cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1473 cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1474 *mesh = cylinder;
1476 return D3D_OK;
1479 HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER* adjacency)
1481 FIXME("(%p, %p, %p): stub\n", device, mesh, adjacency);
1483 return E_NOTIMPL;