d3dx9_36: COM cleanup for the ID3DXSprite iface.
[wine] / dlls / d3dx9_36 / mesh.c
1  /*
2  * Mesh operations specific to D3DX9.
3  *
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  *
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.
13  *
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.
18  *
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
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
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"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
35
36 typedef struct ID3DXMeshImpl
37 {
38     ID3DXMesh ID3DXMesh_iface;
39     LONG ref;
40
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;
50
51 static inline ID3DXMeshImpl *impl_from_ID3DXMesh(ID3DXMesh *iface)
52 {
53     return CONTAINING_RECORD(iface, ID3DXMeshImpl, ID3DXMesh_iface);
54 }
55
56 static HRESULT WINAPI ID3DXMeshImpl_QueryInterface(ID3DXMesh *iface, REFIID riid, LPVOID *object)
57 {
58     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
59
60     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), object);
61
62     if (IsEqualGUID(riid, &IID_IUnknown) ||
63         IsEqualGUID(riid, &IID_ID3DXBaseMesh) ||
64         IsEqualGUID(riid, &IID_ID3DXMesh))
65     {
66         iface->lpVtbl->AddRef(iface);
67         *object = This;
68         return S_OK;
69     }
70
71     WARN("Interface %s not found.\n", debugstr_guid(riid));
72
73     return E_NOINTERFACE;
74 }
75
76 static ULONG WINAPI ID3DXMeshImpl_AddRef(ID3DXMesh *iface)
77 {
78     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
79
80     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
81
82     return InterlockedIncrement(&This->ref);
83 }
84
85 static ULONG WINAPI ID3DXMeshImpl_Release(ID3DXMesh *iface)
86 {
87     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
88     ULONG ref = InterlockedDecrement(&This->ref);
89
90     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
91
92     if (!ref)
93     {
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);
99     }
100
101     return ref;
102 }
103
104 /*** ID3DXBaseMesh ***/
105 static HRESULT WINAPI ID3DXMeshImpl_DrawSubset(ID3DXMesh *iface, DWORD attrib_id)
106 {
107     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
108
109     FIXME("(%p)->(%u): stub\n", This, attrib_id);
110
111     return E_NOTIMPL;
112 }
113
114 static DWORD WINAPI ID3DXMeshImpl_GetNumFaces(ID3DXMesh *iface)
115 {
116     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
117
118     TRACE("(%p)\n", This);
119
120     return This->numfaces;
121 }
122
123 static DWORD WINAPI ID3DXMeshImpl_GetNumVertices(ID3DXMesh *iface)
124 {
125     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
126
127     TRACE("(%p)\n", This);
128
129     return This->numvertices;
130 }
131
132 static DWORD WINAPI ID3DXMeshImpl_GetFVF(ID3DXMesh *iface)
133 {
134     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
135
136     TRACE("(%p)\n", This);
137
138     return This->fvf;
139 }
140
141 static HRESULT WINAPI ID3DXMeshImpl_GetDeclaration(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
142 {
143     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
144     UINT numelements;
145
146     TRACE("(%p)\n", This);
147
148     if (declaration == NULL) return D3DERR_INVALIDCALL;
149
150     return IDirect3DVertexDeclaration9_GetDeclaration(This->vertex_declaration,
151                                                       declaration,
152                                                       &numelements);
153 }
154
155 static DWORD WINAPI ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh *iface)
156 {
157     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
158
159     FIXME("(%p): stub\n", This);
160
161     return 0; /* arbitrary since we cannot return E_NOTIMPL */
162 }
163
164 static DWORD WINAPI ID3DXMeshImpl_GetOptions(ID3DXMesh *iface)
165 {
166     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
167
168     TRACE("(%p)\n", This);
169
170     return This->options;
171 }
172
173 static HRESULT WINAPI ID3DXMeshImpl_GetDevice(ID3DXMesh *iface, LPDIRECT3DDEVICE9 *device)
174 {
175     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
176
177     TRACE("(%p)->(%p)\n", This, device);
178
179     if (device == NULL) return D3DERR_INVALIDCALL;
180     *device = This->device;
181     IDirect3DDevice9_AddRef(This->device);
182
183     return D3D_OK;
184 }
185
186 static HRESULT WINAPI ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh *iface, DWORD options, DWORD fvf, LPDIRECT3DDEVICE9 device, LPD3DXMESH *clone_mesh)
187 {
188     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
189
190     FIXME("(%p)->(%u,%u,%p,%p): stub\n", This, options, fvf, device, clone_mesh);
191
192     return E_NOTIMPL;
193 }
194
195 static HRESULT WINAPI ID3DXMeshImpl_CloneMesh(ID3DXMesh *iface, DWORD options, CONST D3DVERTEXELEMENT9 *declaration, LPDIRECT3DDEVICE9 device,
196                                               LPD3DXMESH *clone_mesh)
197 {
198     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
199
200     FIXME("(%p)->(%u,%p,%p,%p): stub\n", This, options, declaration, device, clone_mesh);
201
202     return E_NOTIMPL;
203 }
204
205 static HRESULT WINAPI ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh *iface, LPDIRECT3DVERTEXBUFFER9 *vertex_buffer)
206 {
207     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
208
209     TRACE("(%p)->(%p)\n", This, vertex_buffer);
210
211     if (vertex_buffer == NULL) return D3DERR_INVALIDCALL;
212     *vertex_buffer = This->vertex_buffer;
213     IDirect3DVertexBuffer9_AddRef(This->vertex_buffer);
214
215     return D3D_OK;
216 }
217
218 static HRESULT WINAPI ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh *iface, LPDIRECT3DINDEXBUFFER9 *index_buffer)
219 {
220     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
221
222     TRACE("(%p)->(%p)\n", This, index_buffer);
223
224     if (index_buffer == NULL) return D3DERR_INVALIDCALL;
225     *index_buffer = This->index_buffer;
226     IDirect3DIndexBuffer9_AddRef(This->index_buffer);
227
228     return D3D_OK;
229 }
230
231 static HRESULT WINAPI ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
232 {
233     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
234
235     TRACE("(%p)->(%u,%p)\n", This, flags, data);
236
237     return IDirect3DVertexBuffer9_Lock(This->vertex_buffer, 0, 0, data, flags);
238 }
239
240 static HRESULT WINAPI ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh *iface)
241 {
242     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
243
244     TRACE("(%p)\n", This);
245
246     return IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
247 }
248
249 static HRESULT WINAPI ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
250 {
251     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
252
253     TRACE("(%p)->(%u,%p)\n", This, flags, data);
254
255     return IDirect3DIndexBuffer9_Lock(This->index_buffer, 0, 0, data, flags);
256 }
257
258 static HRESULT WINAPI ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh *iface)
259 {
260     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
261
262     TRACE("(%p)\n", This);
263
264     return IDirect3DIndexBuffer9_Unlock(This->index_buffer);
265 }
266
267 static HRESULT WINAPI ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTRIBUTERANGE *attrib_table, DWORD *attrib_table_size)
268 {
269     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
270
271     FIXME("(%p)->(%p,%p): stub\n", This, attrib_table, attrib_table_size);
272
273     return E_NOTIMPL;
274 }
275
276 static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency)
277 {
278     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
279
280     FIXME("(%p)->(%p,%p): stub\n", This, point_reps, adjacency);
281
282     return E_NOTIMPL;
283 }
284
285 static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, CONST DWORD *adjacency, DWORD *point_reps)
286 {
287     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
288
289     FIXME("(%p)->(%p,%p): stub\n", This, adjacency, point_reps);
290
291     return E_NOTIMPL;
292 }
293
294 static HRESULT WINAPI ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh *iface, FLOAT epsilon, DWORD *adjacency)
295 {
296     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
297
298     FIXME("(%p)->(%f,%p): stub\n", This, epsilon, adjacency);
299
300     return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI ID3DXMeshImpl_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
304 {
305     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
306
307     FIXME("(%p)->(%p): stub\n", This, declaration);
308
309     return E_NOTIMPL;
310 }
311
312 /*** ID3DXMesh ***/
313 static HRESULT WINAPI ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh *iface, DWORD flags, DWORD **data)
314 {
315     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
316
317     FIXME("(%p)->(%u,%p): stub\n", This, flags, data);
318
319     return E_NOTIMPL;
320 }
321
322 static HRESULT WINAPI ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh *iface)
323 {
324     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
325
326     FIXME("(%p): stub\n", This);
327
328     return E_NOTIMPL;
329 }
330
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)
333 {
334     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
335
336     FIXME("(%p)->(%u,%p,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap, opt_mesh);
337
338     return E_NOTIMPL;
339 }
340
341 static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
342                                                     DWORD *face_remap, LPD3DXBUFFER *vertex_remap)
343 {
344     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
345
346     FIXME("(%p)->(%u,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap);
347
348     return E_NOTIMPL;
349 }
350
351 static HRESULT WINAPI ID3DXMeshImpl_SetAttributeTable(ID3DXMesh *iface, CONST D3DXATTRIBUTERANGE *attrib_table, DWORD attrib_table_size)
352 {
353     ID3DXMeshImpl *This = impl_from_ID3DXMesh(iface);
354
355     FIXME("(%p)->(%p,%u): stub\n", This, attrib_table, attrib_table_size);
356
357     return E_NOTIMPL;
358 }
359
360 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl =
361 {
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
394 };
395
396 /*************************************************************************
397  * D3DXBoxBoundProbe
398  */
399 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
400
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
406
407 International Conference on Computer Graphics and Interactive Techniques  archive
408 ACM SIGGRAPH 2005 Courses
409 Los Angeles, California
410
411 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
412
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.
416 */
417
418 {
419     FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
420
421     div = 1.0f / praydirection->x;
422     if ( div >= 0.0f )
423     {
424         tmin = ( pmin->x - prayposition->x ) * div;
425         tmax = ( pmax->x - prayposition->x ) * div;
426     }
427     else
428     {
429         tmin = ( pmax->x - prayposition->x ) * div;
430         tmax = ( pmin->x - prayposition->x ) * div;
431     }
432
433     if ( tmax < 0.0f ) return FALSE;
434
435     div = 1.0f / praydirection->y;
436     if ( div >= 0.0f )
437     {
438         tymin = ( pmin->y - prayposition->y ) * div;
439         tymax = ( pmax->y - prayposition->y ) * div;
440     }
441     else
442     {
443         tymin = ( pmax->y - prayposition->y ) * div;
444         tymax = ( pmin->y - prayposition->y ) * div;
445     }
446
447     if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
448
449     if ( tymin > tmin ) tmin = tymin;
450     if ( tymax < tmax ) tmax = tymax;
451
452     div = 1.0f / praydirection->z;
453     if ( div >= 0.0f )
454     {
455         tzmin = ( pmin->z - prayposition->z ) * div;
456         tzmax = ( pmax->z - prayposition->z ) * div;
457     }
458     else
459     {
460         tzmin = ( pmax->z - prayposition->z ) * div;
461         tzmax = ( pmin->z - prayposition->z ) * div;
462     }
463
464     if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
465
466     return TRUE;
467 }
468
469 /*************************************************************************
470  * D3DXComputeBoundingBox
471  */
472 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
473 {
474     D3DXVECTOR3 vec;
475     unsigned int i;
476
477     if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
478
479     *pmin = *pfirstposition;
480     *pmax = *pmin;
481
482     for(i=0; i<numvertices; i++)
483     {
484         vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
485
486         if ( vec.x < pmin->x ) pmin->x = vec.x;
487         if ( vec.x > pmax->x ) pmax->x = vec.x;
488
489         if ( vec.y < pmin->y ) pmin->y = vec.y;
490         if ( vec.y > pmax->y ) pmax->y = vec.y;
491
492         if ( vec.z < pmin->z ) pmin->z = vec.z;
493         if ( vec.z > pmax->z ) pmax->z = vec.z;
494     }
495
496     return D3D_OK;
497 }
498
499 /*************************************************************************
500  * D3DXComputeBoundingSphere
501  */
502 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
503 {
504     D3DXVECTOR3 temp, temp1;
505     FLOAT d;
506     unsigned int i;
507
508     if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
509
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;
516
517     for(i=0; i<numvertices; i++)
518     {
519         D3DXVec3Add(&temp1, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
520         temp = temp1;
521     }
522
523     D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
524
525     for(i=0; i<numvertices; i++)
526     {
527         d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
528         if ( d > *pradius ) *pradius = d;
529     }
530     return D3D_OK;
531 }
532
533 static const UINT d3dx_decltype_size[D3DDECLTYPE_UNUSED] =
534 {
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,
552 };
553
554 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
555         D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
556 {
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;
563
564     *offset += d3dx_decltype_size[type];
565     ++(*idx);
566 }
567
568 /*************************************************************************
569  * D3DXDeclaratorFromFVF
570  */
571 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
572 {
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;
578
579     TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
580
581     if (fvf & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) return D3DERR_INVALIDCALL;
582
583     if (fvf & D3DFVF_POSITION_MASK)
584     {
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);
588
589         if (has_blend_idx) --blend_count;
590
591         if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
592                 || (has_blend && blend_count > 4))
593             return D3DERR_INVALIDCALL;
594
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);
599
600         if (has_blend)
601         {
602             switch (blend_count)
603             {
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;
621             }
622
623             if (has_blend_idx)
624             {
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);
629             }
630         }
631     }
632
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);
641
642     for (i = 0; i < tex_count; ++i)
643     {
644         switch ((fvf >> (16 + 2 * i)) & 0x03)
645         {
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;
658         }
659     }
660
661     declaration[idx] = end_element;
662
663     return D3D_OK;
664 }
665
666 /*************************************************************************
667  * D3DXFVFFromDeclarator
668  */
669 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
670 {
671     unsigned int i = 0, texture, offset;
672
673     TRACE("(%p, %p)\n", declaration, fvf);
674
675     *fvf = 0;
676     if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
677     {
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))
682         {
683             return D3DERR_INVALIDCALL;
684         }
685         else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
686                  declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
687         {
688             if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
689             {
690                 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
691             }
692             else
693             {
694                 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
695             }
696             i = 2;
697         }
698         else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
699                  declaration[1].UsageIndex == 0)
700         {
701             if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
702                 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
703             {
704                 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
705                 {
706                     *fvf |= D3DFVF_LASTBETA_UBYTE4;
707                 }
708                 else
709                 {
710                     *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
711                 }
712                 switch (declaration[1].Type)
713                 {
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;
718                 }
719                 i = 3;
720             }
721             else
722             {
723                 switch (declaration[1].Type)
724                 {
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;
729                 }
730                 i = 2;
731             }
732         }
733         else
734         {
735             *fvf |= D3DFVF_XYZ;
736             i = 1;
737         }
738     }
739     else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
740              declaration[0].UsageIndex == 0)
741     {
742         *fvf |= D3DFVF_XYZRHW;
743         i = 1;
744     }
745
746     if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
747     {
748         *fvf |= D3DFVF_NORMAL;
749         i++;
750     }
751     if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
752         declaration[i].UsageIndex == 0)
753     {
754         *fvf |= D3DFVF_PSIZE;
755         i++;
756     }
757     if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
758         declaration[i].UsageIndex == 0)
759     {
760         *fvf |= D3DFVF_DIFFUSE;
761         i++;
762     }
763     if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
764         declaration[i].UsageIndex == 1)
765     {
766         *fvf |= D3DFVF_SPECULAR;
767         i++;
768     }
769
770     for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
771     {
772         if (declaration[i].Stream == 0xFF)
773         {
774             break;
775         }
776         else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
777                  declaration[i].UsageIndex == texture)
778         {
779             *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
780         }
781         else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
782                  declaration[i].UsageIndex == texture)
783         {
784             *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
785         }
786         else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
787                  declaration[i].UsageIndex == texture)
788         {
789             *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
790         }
791         else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
792                  declaration[i].UsageIndex == texture)
793         {
794             *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
795         }
796         else
797         {
798             return D3DERR_INVALIDCALL;
799         }
800     }
801
802     *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
803
804     for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
805          offset += d3dx_decltype_size[declaration[i].Type], i++)
806     {
807         if (declaration[i].Offset != offset)
808         {
809             return D3DERR_INVALIDCALL;
810         }
811     }
812
813     return D3D_OK;
814 }
815
816 /*************************************************************************
817  * D3DXGetFVFVertexSize
818  */
819 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
820 {
821     return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
822 }
823
824 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
825 {
826     DWORD size = 0;
827     UINT i;
828     UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
829
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);
834
835     switch (FVF & D3DFVF_POSITION_MASK)
836     {
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;
845     }
846
847     for (i = 0; i < numTextures; i++)
848     {
849         size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
850     }
851
852     return size;
853 }
854
855 /*************************************************************************
856  * D3DXGetDeclVertexSize
857  */
858 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
859 {
860     const D3DVERTEXELEMENT9 *element;
861     UINT size = 0;
862
863     TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
864
865     if (!decl) return 0;
866
867     for (element = decl; element->Stream != 0xff; ++element)
868     {
869         UINT type_size;
870
871         if (element->Stream != stream_idx) continue;
872
873         if (element->Type >= sizeof(d3dx_decltype_size) / sizeof(*d3dx_decltype_size))
874         {
875             FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
876             continue;
877         }
878
879         type_size = d3dx_decltype_size[element->Type];
880         if (element->Offset + type_size > size) size = element->Offset + type_size;
881     }
882
883     return size;
884 }
885
886 /*************************************************************************
887  * D3DXGetDeclLength
888  */
889 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
890 {
891     const D3DVERTEXELEMENT9 *element;
892
893     TRACE("decl %p\n", decl);
894
895     /* null decl results in exception on Windows XP */
896
897     for (element = decl; element->Stream != 0xff; ++element);
898
899     return element - decl;
900 }
901
902 /*************************************************************************
903  * D3DXIntersectTri
904  */
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)
906 {
907     D3DXMATRIX m;
908     D3DXVECTOR4 vec;
909
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;
926
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;
931
932     if ( D3DXMatrixInverse(&m, NULL, &m) )
933     {
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) )
936         {
937             *pu = vec.x;
938             *pv = vec.y;
939             *pdist = fabs( vec.z );
940             return TRUE;
941         }
942     }
943
944     return FALSE;
945 }
946
947 /*************************************************************************
948  * D3DXSphereBoundProbe
949  */
950 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
951 {
952     D3DXVECTOR3 difference;
953     FLOAT a, b, c, d;
954
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;
960
961     if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
962     return TRUE;
963 }
964
965 /*************************************************************************
966  * D3DXCreateMesh
967  */
968 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options, CONST D3DVERTEXELEMENT9 *declaration,
969                               LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
970 {
971     HRESULT hr;
972     DWORD fvf;
973     IDirect3DVertexDeclaration9 *vertex_declaration;
974     IDirect3DVertexBuffer9 *vertex_buffer;
975     IDirect3DIndexBuffer9 *index_buffer;
976     ID3DXMeshImpl *object;
977
978     TRACE("(%d, %d, %d, %p, %p, %p)\n", numfaces, numvertices, options, declaration, device, mesh);
979
980     if (numfaces == 0 || numvertices == 0 || declaration == NULL || device == NULL || mesh == NULL)
981     {
982         return D3DERR_INVALIDCALL;
983     }
984
985     hr = D3DXFVFFromDeclarator(declaration, &fvf);
986     if (hr != D3D_OK)
987     {
988         fvf = 0;
989     }
990
991     /* Create vertex declaration */
992     hr = IDirect3DDevice9_CreateVertexDeclaration(device,
993                                                   declaration,
994                                                   &vertex_declaration);
995     if (FAILED(hr))
996     {
997         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
998         return hr;
999     }
1000
1001     /* Create vertex buffer */
1002     hr = IDirect3DDevice9_CreateVertexBuffer(device,
1003                                              numvertices * D3DXGetDeclVertexSize(declaration, declaration[0].Stream),
1004                                              0,
1005                                              fvf,
1006                                              D3DPOOL_MANAGED,
1007                                              &vertex_buffer,
1008                                              NULL);
1009     if (FAILED(hr))
1010     {
1011         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1012         IDirect3DVertexDeclaration9_Release(vertex_declaration);
1013         return hr;
1014     }
1015
1016     /* Create index buffer */
1017     hr = IDirect3DDevice9_CreateIndexBuffer(device,
1018                                             numfaces * 6, /* 3 vertices per triangle, 2 triangles per face */
1019                                             0,
1020                                             D3DFMT_INDEX16,
1021                                             D3DPOOL_MANAGED,
1022                                             &index_buffer,
1023                                             NULL);
1024     if (FAILED(hr))
1025     {
1026         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1027         IDirect3DVertexBuffer9_Release(vertex_buffer);
1028         IDirect3DVertexDeclaration9_Release(vertex_declaration);
1029         return hr;
1030     }
1031
1032     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXMeshImpl));
1033     if (object == NULL)
1034     {
1035         IDirect3DIndexBuffer9_Release(index_buffer);
1036         IDirect3DVertexBuffer9_Release(vertex_buffer);
1037         IDirect3DVertexDeclaration9_Release(vertex_declaration);
1038         *mesh = NULL;
1039         return E_OUTOFMEMORY;
1040     }
1041     object->ID3DXMesh_iface.lpVtbl = &D3DXMesh_Vtbl;
1042     object->ref = 1;
1043
1044     object->numfaces = numfaces;
1045     object->numvertices = numvertices;
1046     object->options = options;
1047     object->fvf = fvf;
1048     object->device = device;
1049     IDirect3DDevice9_AddRef(device);
1050
1051     object->vertex_declaration = vertex_declaration;
1052     object->vertex_buffer = vertex_buffer;
1053     object->index_buffer = index_buffer;
1054
1055     *mesh = &object->ID3DXMesh_iface;
1056
1057     return D3D_OK;
1058 }
1059
1060 /*************************************************************************
1061  * D3DXCreateMeshFVF
1062  */
1063 HRESULT WINAPI D3DXCreateMeshFVF(DWORD numfaces, DWORD numvertices, DWORD options, DWORD fvf,
1064                                  LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
1065 {
1066     HRESULT hr;
1067     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
1068
1069     TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces, numvertices, options, fvf, device, mesh);
1070
1071     hr = D3DXDeclaratorFromFVF(fvf, declaration);
1072     if (FAILED(hr)) return hr;
1073
1074     return D3DXCreateMesh(numfaces, numvertices, options, declaration, device, mesh);
1075 }
1076
1077 HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height,
1078                              FLOAT depth, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1079 {
1080     FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device, width, height, depth, mesh, adjacency);
1081
1082     return E_NOTIMPL;
1083 }
1084
1085 struct vertex
1086 {
1087     D3DXVECTOR3 position;
1088     D3DXVECTOR3 normal;
1089 };
1090
1091 typedef WORD face[3];
1092
1093 struct sincos_table
1094 {
1095     float *sin;
1096     float *cos;
1097 };
1098
1099 static void free_sincos_table(struct sincos_table *sincos_table)
1100 {
1101     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1102     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1103 }
1104
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)
1107 {
1108     float angle;
1109     int i;
1110
1111     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1112     if (!sincos_table->sin)
1113     {
1114         return FALSE;
1115     }
1116     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1117     if (!sincos_table->cos)
1118     {
1119         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1120         return FALSE;
1121     }
1122
1123     angle = angle_start;
1124     for (i = 0; i < n; i++)
1125     {
1126         sincos_table->sin[i] = sin(angle);
1127         sincos_table->cos[i] = cos(angle);
1128         angle += angle_step;
1129     }
1130
1131     return TRUE;
1132 }
1133
1134 static WORD vertex_index(UINT slices, int slice, int stack)
1135 {
1136     return stack*slices+slice+1;
1137 }
1138
1139 HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices,
1140                                 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1141 {
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;
1152
1153     TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency);
1154
1155     if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh)
1156     {
1157         return D3DERR_INVALIDCALL;
1158     }
1159
1160     if (adjacency)
1161     {
1162         FIXME("Case of adjacency != NULL not implemented.\n");
1163         return E_NOTIMPL;
1164     }
1165
1166     number_of_vertices = 2 + slices * (stacks-1);
1167     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1168
1169     hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1170                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere);
1171     if (FAILED(hr))
1172     {
1173         return hr;
1174     }
1175
1176     hr = sphere->lpVtbl->LockVertexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1177     if (FAILED(hr))
1178     {
1179         sphere->lpVtbl->Release(sphere);
1180         return hr;
1181     }
1182
1183     hr = sphere->lpVtbl->LockIndexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&faces);
1184     if (FAILED(hr))
1185     {
1186         sphere->lpVtbl->UnlockVertexBuffer(sphere);
1187         sphere->lpVtbl->Release(sphere);
1188         return hr;
1189     }
1190
1191     /* phi = angle on xz plane wrt z axis */
1192     phi_step = -2 * M_PI / slices;
1193     phi_start = M_PI / 2;
1194
1195     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1196     {
1197         sphere->lpVtbl->UnlockIndexBuffer(sphere);
1198         sphere->lpVtbl->UnlockVertexBuffer(sphere);
1199         sphere->lpVtbl->Release(sphere);
1200         return E_OUTOFMEMORY;
1201     }
1202
1203     /* theta = angle on xy plane wrt x axis */
1204     theta_step = M_PI / stacks;
1205     theta = theta_step;
1206
1207     vertex = 0;
1208     face = 0;
1209     stack = 0;
1210
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++;
1218
1219     for (stack = 0; stack < stacks - 1; stack++)
1220     {
1221         sin_theta = sin(theta);
1222         cos_theta = cos(theta);
1223
1224         for (slice = 0; slice < slices; slice++)
1225         {
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++;
1233
1234             if (slice > 0)
1235             {
1236                 if (stack == 0)
1237                 {
1238                     /* top stack is triangle fan */
1239                     faces[face][0] = 0;
1240                     faces[face][1] = slice + 1;
1241                     faces[face][2] = slice;
1242                     face++;
1243                 }
1244                 else
1245                 {
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++;
1251
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++;
1256                 }
1257             }
1258         }
1259
1260         theta += theta_step;
1261
1262         if (stack == 0)
1263         {
1264             faces[face][0] = 0;
1265             faces[face][1] = 1;
1266             faces[face][2] = slice;
1267             face++;
1268         }
1269         else
1270         {
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++;
1275
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++;
1280         }
1281     }
1282
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;
1289
1290     /* bottom stack is triangle fan */
1291     for (slice = 1; slice < slices; slice++)
1292     {
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++;
1297     }
1298
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;
1302
1303     free_sincos_table(&phi);
1304     sphere->lpVtbl->UnlockIndexBuffer(sphere);
1305     sphere->lpVtbl->UnlockVertexBuffer(sphere);
1306     *mesh = sphere;
1307
1308     return D3D_OK;
1309 }
1310
1311 HRESULT WINAPI D3DXCreateCylinder(LPDIRECT3DDEVICE9 device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices,
1312                                   UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1313 {
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;
1325
1326     TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device, radius1, radius2, length, slices, stacks, mesh, adjacency);
1327
1328     if (device == NULL || radius1 < 0.0f || radius2 < 0.0f || length < 0.0f || slices < 2 || stacks < 1 || mesh == NULL)
1329     {
1330         return D3DERR_INVALIDCALL;
1331     }
1332
1333     if (adjacency)
1334     {
1335         FIXME("Case of adjacency != NULL not implemented.\n");
1336         return E_NOTIMPL;
1337     }
1338
1339     number_of_vertices = 2 + (slices * (3 + stacks));
1340     number_of_faces = 2 * slices + stacks * (2 * slices);
1341
1342     hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1343                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &cylinder);
1344     if (FAILED(hr))
1345     {
1346         return hr;
1347     }
1348
1349     hr = cylinder->lpVtbl->LockVertexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1350     if (FAILED(hr))
1351     {
1352         cylinder->lpVtbl->Release(cylinder);
1353         return hr;
1354     }
1355
1356     hr = cylinder->lpVtbl->LockIndexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&faces);
1357     if (FAILED(hr))
1358     {
1359         cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1360         cylinder->lpVtbl->Release(cylinder);
1361         return hr;
1362     }
1363
1364     /* theta = angle on xy plane wrt x axis */
1365     theta_step = -2 * M_PI / slices;
1366     theta_start = M_PI / 2;
1367
1368     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1369     {
1370         cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1371         cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1372         cylinder->lpVtbl->Release(cylinder);
1373         return E_OUTOFMEMORY;
1374     }
1375
1376     vertex = 0;
1377     face = 0;
1378     stack = 0;
1379
1380     delta_radius = radius1 - radius2;
1381     radius = radius1;
1382     radius_step = delta_radius / stacks;
1383
1384     z = -length / 2;
1385     z_step = length / stacks;
1386     z_normal = delta_radius / length;
1387     if (isnan(z_normal))
1388     {
1389         z_normal = 0.0f;
1390     }
1391
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;
1398
1399     for (slice = 0; slice < slices; slice++, vertex++)
1400     {
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;
1407
1408         if (slice > 0)
1409         {
1410             faces[face][0] = 0;
1411             faces[face][1] = slice;
1412             faces[face++][2] = slice + 1;
1413         }
1414     }
1415
1416     faces[face][0] = 0;
1417     faces[face][1] = slice;
1418     faces[face++][2] = 1;
1419
1420     for (stack = 1; stack <= stacks+1; stack++)
1421     {
1422         for (slice = 0; slice < slices; slice++, vertex++)
1423         {
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;
1431
1432             if (stack > 1 && slice > 0)
1433             {
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);
1437
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);
1441             }
1442         }
1443
1444         if (stack > 1)
1445         {
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);
1449
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);
1453         }
1454
1455         if (stack < stacks + 1)
1456         {
1457             z += z_step;
1458             radius -= radius_step;
1459         }
1460     }
1461
1462     for (slice = 0; slice < slices; slice++, vertex++)
1463     {
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;
1470
1471         if (slice > 0)
1472         {
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);
1476         }
1477     }
1478
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;
1485
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);
1489
1490     free_sincos_table(&theta);
1491     cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1492     cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1493     *mesh = cylinder;
1494
1495     return D3D_OK;
1496 }
1497
1498 HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER* adjacency)
1499 {
1500     FIXME("(%p, %p, %p): stub\n", device, mesh, adjacency);
1501
1502     return E_NOTIMPL;
1503 }