dinput/tests: Skip acquire tests when not running in the foreground.
[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 /*** IUnknown methods ***/
37 static HRESULT WINAPI ID3DXMeshImpl_QueryInterface(ID3DXMesh *iface, REFIID riid, LPVOID *object)
38 {
39     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
40
41     TRACE("(%p)->(%s, %p)\n", This, debugstr_guid(riid), object);
42
43     if (IsEqualGUID(riid, &IID_IUnknown) ||
44         IsEqualGUID(riid, &IID_ID3DXBaseMesh) ||
45         IsEqualGUID(riid, &IID_ID3DXMesh))
46     {
47         iface->lpVtbl->AddRef(iface);
48         *object = This;
49         return S_OK;
50     }
51
52     WARN("Interface %s not found.\n", debugstr_guid(riid));
53
54     return E_NOINTERFACE;
55 }
56
57 static ULONG WINAPI ID3DXMeshImpl_AddRef(ID3DXMesh *iface)
58 {
59     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
60
61     TRACE("(%p)->(): AddRef from %d\n", This, This->ref);
62
63     return InterlockedIncrement(&This->ref);
64 }
65
66 static ULONG WINAPI ID3DXMeshImpl_Release(ID3DXMesh *iface)
67 {
68     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
69     ULONG ref = InterlockedDecrement(&This->ref);
70
71     TRACE("(%p)->(): Release from %d\n", This, ref + 1);
72
73     if (!ref)
74     {
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);
80     }
81
82     return ref;
83 }
84
85 /*** ID3DXBaseMesh ***/
86 static HRESULT WINAPI ID3DXMeshImpl_DrawSubset(ID3DXMesh *iface, DWORD attrib_id)
87 {
88     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
89
90     FIXME("(%p)->(%u): stub\n", This, attrib_id);
91
92     return E_NOTIMPL;
93 }
94
95 static DWORD WINAPI ID3DXMeshImpl_GetNumFaces(ID3DXMesh *iface)
96 {
97     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
98
99     TRACE("(%p)\n", This);
100
101     return This->numfaces;
102 }
103
104 static DWORD WINAPI ID3DXMeshImpl_GetNumVertices(ID3DXMesh *iface)
105 {
106     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
107
108     TRACE("(%p)\n", This);
109
110     return This->numvertices;
111 }
112
113 static DWORD WINAPI ID3DXMeshImpl_GetFVF(ID3DXMesh *iface)
114 {
115     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
116
117     TRACE("(%p)\n", This);
118
119     return This->fvf;
120 }
121
122 static HRESULT WINAPI ID3DXMeshImpl_GetDeclaration(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
123 {
124     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
125     UINT numelements;
126
127     TRACE("(%p)\n", This);
128
129     if (declaration == NULL) return D3DERR_INVALIDCALL;
130
131     return IDirect3DVertexDeclaration9_GetDeclaration(This->vertex_declaration,
132                                                       declaration,
133                                                       &numelements);
134 }
135
136 static DWORD WINAPI ID3DXMeshImpl_GetNumBytesPerVertex(ID3DXMesh *iface)
137 {
138     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
139
140     FIXME("(%p): stub\n", This);
141
142     return 0; /* arbitrary since we cannot return E_NOTIMPL */
143 }
144
145 static DWORD WINAPI ID3DXMeshImpl_GetOptions(ID3DXMesh *iface)
146 {
147     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
148
149     TRACE("(%p)\n", This);
150
151     return This->options;
152 }
153
154 static HRESULT WINAPI ID3DXMeshImpl_GetDevice(ID3DXMesh *iface, LPDIRECT3DDEVICE9 *device)
155 {
156     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
157
158     TRACE("(%p)->(%p)\n", This, device);
159
160     if (device == NULL) return D3DERR_INVALIDCALL;
161     *device = This->device;
162     IDirect3DDevice9_AddRef(This->device);
163
164     return D3D_OK;
165 }
166
167 static HRESULT WINAPI ID3DXMeshImpl_CloneMeshFVF(ID3DXMesh *iface, DWORD options, DWORD fvf, LPDIRECT3DDEVICE9 device, LPD3DXMESH *clone_mesh)
168 {
169     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
170
171     FIXME("(%p)->(%u,%u,%p,%p): stub\n", This, options, fvf, device, clone_mesh);
172
173     return E_NOTIMPL;
174 }
175
176 static HRESULT WINAPI ID3DXMeshImpl_CloneMesh(ID3DXMesh *iface, DWORD options, CONST D3DVERTEXELEMENT9 *declaration, LPDIRECT3DDEVICE9 device,
177                                               LPD3DXMESH *clone_mesh)
178 {
179     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
180
181     FIXME("(%p)->(%u,%p,%p,%p): stub\n", This, options, declaration, device, clone_mesh);
182
183     return E_NOTIMPL;
184 }
185
186 static HRESULT WINAPI ID3DXMeshImpl_GetVertexBuffer(ID3DXMesh *iface, LPDIRECT3DVERTEXBUFFER9 *vertex_buffer)
187 {
188     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
189
190     TRACE("(%p)->(%p)\n", This, vertex_buffer);
191
192     if (vertex_buffer == NULL) return D3DERR_INVALIDCALL;
193     *vertex_buffer = This->vertex_buffer;
194     IDirect3DVertexBuffer9_AddRef(This->vertex_buffer);
195
196     return D3D_OK;
197 }
198
199 static HRESULT WINAPI ID3DXMeshImpl_GetIndexBuffer(ID3DXMesh *iface, LPDIRECT3DINDEXBUFFER9 *index_buffer)
200 {
201     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
202
203     TRACE("(%p)->(%p)\n", This, index_buffer);
204
205     if (index_buffer == NULL) return D3DERR_INVALIDCALL;
206     *index_buffer = This->index_buffer;
207     IDirect3DIndexBuffer9_AddRef(This->index_buffer);
208
209     return D3D_OK;
210 }
211
212 static HRESULT WINAPI ID3DXMeshImpl_LockVertexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
213 {
214     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
215
216     TRACE("(%p)->(%u,%p)\n", This, flags, data);
217
218     return IDirect3DVertexBuffer9_Lock(This->vertex_buffer, 0, 0, data, flags);
219 }
220
221 static HRESULT WINAPI ID3DXMeshImpl_UnlockVertexBuffer(ID3DXMesh *iface)
222 {
223     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
224
225     TRACE("(%p)\n", This);
226
227     return IDirect3DVertexBuffer9_Unlock(This->vertex_buffer);
228 }
229
230 static HRESULT WINAPI ID3DXMeshImpl_LockIndexBuffer(ID3DXMesh *iface, DWORD flags, LPVOID *data)
231 {
232     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
233
234     TRACE("(%p)->(%u,%p)\n", This, flags, data);
235
236     return IDirect3DIndexBuffer9_Lock(This->index_buffer, 0, 0, data, flags);
237 }
238
239 static HRESULT WINAPI ID3DXMeshImpl_UnlockIndexBuffer(ID3DXMesh *iface)
240 {
241     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
242
243     TRACE("(%p)\n", This);
244
245     return IDirect3DIndexBuffer9_Unlock(This->index_buffer);
246 }
247
248 static HRESULT WINAPI ID3DXMeshImpl_GetAttributeTable(ID3DXMesh *iface, D3DXATTRIBUTERANGE *attrib_table, DWORD *attrib_table_size)
249 {
250     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
251
252     FIXME("(%p)->(%p,%p): stub\n", This, attrib_table, attrib_table_size);
253
254     return E_NOTIMPL;
255 }
256
257 static HRESULT WINAPI ID3DXMeshImpl_ConvertPointRepsToAdjacency(ID3DXMesh *iface, CONST DWORD *point_reps, DWORD *adjacency)
258 {
259     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
260
261     FIXME("(%p)->(%p,%p): stub\n", This, point_reps, adjacency);
262
263     return E_NOTIMPL;
264 }
265
266 static HRESULT WINAPI ID3DXMeshImpl_ConvertAdjacencyToPointReps(ID3DXMesh *iface, CONST DWORD *adjacency, DWORD *point_reps)
267 {
268     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
269
270     FIXME("(%p)->(%p,%p): stub\n", This, adjacency, point_reps);
271
272     return E_NOTIMPL;
273 }
274
275 static HRESULT WINAPI ID3DXMeshImpl_GenerateAdjacency(ID3DXMesh *iface, FLOAT epsilon, DWORD *adjacency)
276 {
277     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
278
279     FIXME("(%p)->(%f,%p): stub\n", This, epsilon, adjacency);
280
281     return E_NOTIMPL;
282 }
283
284 static HRESULT WINAPI ID3DXMeshImpl_UpdateSemantics(ID3DXMesh *iface, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
285 {
286     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
287
288     FIXME("(%p)->(%p): stub\n", This, declaration);
289
290     return E_NOTIMPL;
291 }
292
293 /*** ID3DXMesh ***/
294 static HRESULT WINAPI ID3DXMeshImpl_LockAttributeBuffer(ID3DXMesh *iface, DWORD flags, DWORD **data)
295 {
296     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
297
298     FIXME("(%p)->(%u,%p): stub\n", This, flags, data);
299
300     return E_NOTIMPL;
301 }
302
303 static HRESULT WINAPI ID3DXMeshImpl_UnlockAttributeBuffer(ID3DXMesh *iface)
304 {
305     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
306
307     FIXME("(%p): stub\n", This);
308
309     return E_NOTIMPL;
310 }
311
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)
314 {
315     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
316
317     FIXME("(%p)->(%u,%p,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap, opt_mesh);
318
319     return E_NOTIMPL;
320 }
321
322 static HRESULT WINAPI ID3DXMeshImpl_OptimizeInplace(ID3DXMesh *iface, DWORD flags, CONST DWORD *adjacency_in, DWORD *adjacency_out,
323                                                     DWORD *face_remap, LPD3DXBUFFER *vertex_remap)
324 {
325     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
326
327     FIXME("(%p)->(%u,%p,%p,%p,%p): stub\n", This, flags, adjacency_in, adjacency_out, face_remap, vertex_remap);
328
329     return E_NOTIMPL;
330 }
331
332 static HRESULT WINAPI ID3DXMeshImpl_SetAttributeTable(ID3DXMesh *iface, CONST D3DXATTRIBUTERANGE *attrib_table, DWORD attrib_table_size)
333 {
334     ID3DXMeshImpl *This = (ID3DXMeshImpl *)iface;
335
336     FIXME("(%p)->(%p,%u): stub\n", This, attrib_table, attrib_table_size);
337
338     return E_NOTIMPL;
339 }
340
341 static const struct ID3DXMeshVtbl D3DXMesh_Vtbl =
342 {
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
375 };
376
377 /*************************************************************************
378  * D3DXBoxBoundProbe
379  */
380 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
381
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
387
388 International Conference on Computer Graphics and Interactive Techniques  archive
389 ACM SIGGRAPH 2005 Courses
390 Los Angeles, California
391
392 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
393
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.
397 */
398
399 {
400     FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
401
402     div = 1.0f / praydirection->x;
403     if ( div >= 0.0f )
404     {
405         tmin = ( pmin->x - prayposition->x ) * div;
406         tmax = ( pmax->x - prayposition->x ) * div;
407     }
408     else
409     {
410         tmin = ( pmax->x - prayposition->x ) * div;
411         tmax = ( pmin->x - prayposition->x ) * div;
412     }
413
414     if ( tmax < 0.0f ) return FALSE;
415
416     div = 1.0f / praydirection->y;
417     if ( div >= 0.0f )
418     {
419         tymin = ( pmin->y - prayposition->y ) * div;
420         tymax = ( pmax->y - prayposition->y ) * div;
421     }
422     else
423     {
424         tymin = ( pmax->y - prayposition->y ) * div;
425         tymax = ( pmin->y - prayposition->y ) * div;
426     }
427
428     if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
429
430     if ( tymin > tmin ) tmin = tymin;
431     if ( tymax < tmax ) tmax = tymax;
432
433     div = 1.0f / praydirection->z;
434     if ( div >= 0.0f )
435     {
436         tzmin = ( pmin->z - prayposition->z ) * div;
437         tzmax = ( pmax->z - prayposition->z ) * div;
438     }
439     else
440     {
441         tzmin = ( pmax->z - prayposition->z ) * div;
442         tzmax = ( pmin->z - prayposition->z ) * div;
443     }
444
445     if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
446
447     return TRUE;
448 }
449
450 /*************************************************************************
451  * D3DXComputeBoundingBox
452  */
453 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
454 {
455     D3DXVECTOR3 vec;
456     unsigned int i;
457
458     if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
459
460     *pmin = *pfirstposition;
461     *pmax = *pmin;
462
463     for(i=0; i<numvertices; i++)
464     {
465         vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
466
467         if ( vec.x < pmin->x ) pmin->x = vec.x;
468         if ( vec.x > pmax->x ) pmax->x = vec.x;
469
470         if ( vec.y < pmin->y ) pmin->y = vec.y;
471         if ( vec.y > pmax->y ) pmax->y = vec.y;
472
473         if ( vec.z < pmin->z ) pmin->z = vec.z;
474         if ( vec.z > pmax->z ) pmax->z = vec.z;
475     }
476
477     return D3D_OK;
478 }
479
480 /*************************************************************************
481  * D3DXComputeBoundingSphere
482  */
483 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
484 {
485     D3DXVECTOR3 temp, temp1;
486     FLOAT d;
487     unsigned int i;
488
489     if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
490
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;
497
498     for(i=0; i<numvertices; i++)
499     {
500         D3DXVec3Add(&temp1, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
501         temp = temp1;
502     }
503
504     D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
505
506     for(i=0; i<numvertices; i++)
507     {
508         d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
509         if ( d > *pradius ) *pradius = d;
510     }
511     return D3D_OK;
512 }
513
514 static const UINT d3dx_decltype_size[D3DDECLTYPE_UNUSED] =
515 {
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,
533 };
534
535 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
536         D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
537 {
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;
544
545     *offset += d3dx_decltype_size[type];
546     ++(*idx);
547 }
548
549 /*************************************************************************
550  * D3DXDeclaratorFromFVF
551  */
552 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
553 {
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;
559
560     TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
561
562     if (fvf & (D3DFVF_RESERVED0 | D3DFVF_RESERVED2)) return D3DERR_INVALIDCALL;
563
564     if (fvf & D3DFVF_POSITION_MASK)
565     {
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);
569
570         if (has_blend_idx) --blend_count;
571
572         if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
573                 || (has_blend && blend_count > 4))
574             return D3DERR_INVALIDCALL;
575
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);
580
581         if (has_blend)
582         {
583             switch (blend_count)
584             {
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;
602             }
603
604             if (has_blend_idx)
605             {
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);
610             }
611         }
612     }
613
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);
622
623     for (i = 0; i < tex_count; ++i)
624     {
625         switch ((fvf >> (16 + 2 * i)) & 0x03)
626         {
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;
639         }
640     }
641
642     declaration[idx] = end_element;
643
644     return D3D_OK;
645 }
646
647 /*************************************************************************
648  * D3DXFVFFromDeclarator
649  */
650 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
651 {
652     unsigned int i = 0, texture, offset;
653
654     TRACE("(%p, %p)\n", declaration, fvf);
655
656     *fvf = 0;
657     if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
658     {
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))
663         {
664             return D3DERR_INVALIDCALL;
665         }
666         else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
667                  declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
668         {
669             if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
670             {
671                 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
672             }
673             else
674             {
675                 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
676             }
677             i = 2;
678         }
679         else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
680                  declaration[1].UsageIndex == 0)
681         {
682             if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
683                 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
684             {
685                 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
686                 {
687                     *fvf |= D3DFVF_LASTBETA_UBYTE4;
688                 }
689                 else
690                 {
691                     *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
692                 }
693                 switch (declaration[1].Type)
694                 {
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;
699                 }
700                 i = 3;
701             }
702             else
703             {
704                 switch (declaration[1].Type)
705                 {
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;
710                 }
711                 i = 2;
712             }
713         }
714         else
715         {
716             *fvf |= D3DFVF_XYZ;
717             i = 1;
718         }
719     }
720     else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
721              declaration[0].UsageIndex == 0)
722     {
723         *fvf |= D3DFVF_XYZRHW;
724         i = 1;
725     }
726
727     if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
728     {
729         *fvf |= D3DFVF_NORMAL;
730         i++;
731     }
732     if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
733         declaration[i].UsageIndex == 0)
734     {
735         *fvf |= D3DFVF_PSIZE;
736         i++;
737     }
738     if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
739         declaration[i].UsageIndex == 0)
740     {
741         *fvf |= D3DFVF_DIFFUSE;
742         i++;
743     }
744     if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
745         declaration[i].UsageIndex == 1)
746     {
747         *fvf |= D3DFVF_SPECULAR;
748         i++;
749     }
750
751     for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
752     {
753         if (declaration[i].Stream == 0xFF)
754         {
755             break;
756         }
757         else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
758                  declaration[i].UsageIndex == texture)
759         {
760             *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
761         }
762         else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
763                  declaration[i].UsageIndex == texture)
764         {
765             *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
766         }
767         else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
768                  declaration[i].UsageIndex == texture)
769         {
770             *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
771         }
772         else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
773                  declaration[i].UsageIndex == texture)
774         {
775             *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
776         }
777         else
778         {
779             return D3DERR_INVALIDCALL;
780         }
781     }
782
783     *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
784
785     for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
786          offset += d3dx_decltype_size[declaration[i].Type], i++)
787     {
788         if (declaration[i].Offset != offset)
789         {
790             return D3DERR_INVALIDCALL;
791         }
792     }
793
794     return D3D_OK;
795 }
796
797 /*************************************************************************
798  * D3DXGetFVFVertexSize
799  */
800 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
801 {
802     return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
803 }
804
805 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
806 {
807     DWORD size = 0;
808     UINT i;
809     UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
810
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);
815
816     switch (FVF & D3DFVF_POSITION_MASK)
817     {
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;
826     }
827
828     for (i = 0; i < numTextures; i++)
829     {
830         size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
831     }
832
833     return size;
834 }
835
836 /*************************************************************************
837  * D3DXGetDeclVertexSize
838  */
839 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
840 {
841     const D3DVERTEXELEMENT9 *element;
842     UINT size = 0;
843
844     TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
845
846     if (!decl) return 0;
847
848     for (element = decl; element->Stream != 0xff; ++element)
849     {
850         UINT type_size;
851
852         if (element->Stream != stream_idx) continue;
853
854         if (element->Type >= sizeof(d3dx_decltype_size) / sizeof(*d3dx_decltype_size))
855         {
856             FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
857             continue;
858         }
859
860         type_size = d3dx_decltype_size[element->Type];
861         if (element->Offset + type_size > size) size = element->Offset + type_size;
862     }
863
864     return size;
865 }
866
867 /*************************************************************************
868  * D3DXGetDeclLength
869  */
870 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
871 {
872     const D3DVERTEXELEMENT9 *element;
873
874     TRACE("decl %p\n", decl);
875
876     /* null decl results in exception on Windows XP */
877
878     for (element = decl; element->Stream != 0xff; ++element);
879
880     return element - decl;
881 }
882
883 /*************************************************************************
884  * D3DXIntersectTri
885  */
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)
887 {
888     D3DXMATRIX m;
889     D3DXVECTOR4 vec;
890
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;
907
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;
912
913     if ( D3DXMatrixInverse(&m, NULL, &m) )
914     {
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) )
917         {
918             *pu = vec.x;
919             *pv = vec.y;
920             *pdist = fabs( vec.z );
921             return TRUE;
922         }
923     }
924
925     return FALSE;
926 }
927
928 /*************************************************************************
929  * D3DXSphereBoundProbe
930  */
931 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
932 {
933     D3DXVECTOR3 difference;
934     FLOAT a, b, c, d;
935
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;
941
942     if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
943     return TRUE;
944 }
945
946 /*************************************************************************
947  * D3DXCreateMesh
948  */
949 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options, CONST D3DVERTEXELEMENT9 *declaration,
950                               LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
951 {
952     HRESULT hr;
953     DWORD fvf;
954     IDirect3DVertexDeclaration9 *vertex_declaration;
955     IDirect3DVertexBuffer9 *vertex_buffer;
956     IDirect3DIndexBuffer9 *index_buffer;
957     ID3DXMeshImpl *object;
958
959     TRACE("(%d, %d, %d, %p, %p, %p)\n", numfaces, numvertices, options, declaration, device, mesh);
960
961     if (numfaces == 0 || numvertices == 0 || declaration == NULL || device == NULL || mesh == NULL)
962     {
963         return D3DERR_INVALIDCALL;
964     }
965
966     hr = D3DXFVFFromDeclarator(declaration, &fvf);
967     if (hr != D3D_OK)
968     {
969         fvf = 0;
970     }
971
972     /* Create vertex declaration */
973     hr = IDirect3DDevice9_CreateVertexDeclaration(device,
974                                                   declaration,
975                                                   &vertex_declaration);
976     if (FAILED(hr))
977     {
978         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexDeclaration.\n",hr);
979         return hr;
980     }
981
982     /* Create vertex buffer */
983     hr = IDirect3DDevice9_CreateVertexBuffer(device,
984                                              numvertices * D3DXGetDeclVertexSize(declaration, declaration[0].Stream),
985                                              0,
986                                              fvf,
987                                              D3DPOOL_MANAGED,
988                                              &vertex_buffer,
989                                              NULL);
990     if (FAILED(hr))
991     {
992         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
993         IDirect3DVertexDeclaration9_Release(vertex_declaration);
994         return hr;
995     }
996
997     /* Create index buffer */
998     hr = IDirect3DDevice9_CreateIndexBuffer(device,
999                                             numfaces * 6, /* 3 vertices per triangle, 2 triangles per face */
1000                                             0,
1001                                             D3DFMT_INDEX16,
1002                                             D3DPOOL_MANAGED,
1003                                             &index_buffer,
1004                                             NULL);
1005     if (FAILED(hr))
1006     {
1007         WARN("Unexpected return value %x from IDirect3DDevice9_CreateVertexBuffer.\n",hr);
1008         IDirect3DVertexBuffer9_Release(vertex_buffer);
1009         IDirect3DVertexDeclaration9_Release(vertex_declaration);
1010         return hr;
1011     }
1012
1013     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ID3DXMeshImpl));
1014     if (object == NULL)
1015     {
1016         IDirect3DIndexBuffer9_Release(index_buffer);
1017         IDirect3DVertexBuffer9_Release(vertex_buffer);
1018         IDirect3DVertexDeclaration9_Release(vertex_declaration);
1019         *mesh = NULL;
1020         return E_OUTOFMEMORY;
1021     }
1022     object->lpVtbl = &D3DXMesh_Vtbl;
1023     object->ref = 1;
1024
1025     object->numfaces = numfaces;
1026     object->numvertices = numvertices;
1027     object->options = options;
1028     object->fvf = fvf;
1029     object->device = device;
1030     IDirect3DDevice9_AddRef(device);
1031
1032     object->vertex_declaration = vertex_declaration;
1033     object->vertex_buffer = vertex_buffer;
1034     object->index_buffer = index_buffer;
1035
1036     *mesh = (ID3DXMesh*)object;
1037
1038     return D3D_OK;
1039 }
1040
1041 /*************************************************************************
1042  * D3DXCreateMeshFVF
1043  */
1044 HRESULT WINAPI D3DXCreateMeshFVF(DWORD numfaces, DWORD numvertices, DWORD options, DWORD fvf,
1045                                  LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
1046 {
1047     HRESULT hr;
1048     D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE];
1049
1050     TRACE("(%u, %u, %u, %u, %p, %p)\n", numfaces, numvertices, options, fvf, device, mesh);
1051
1052     hr = D3DXDeclaratorFromFVF(fvf, declaration);
1053     if (FAILED(hr)) return hr;
1054
1055     return D3DXCreateMesh(numfaces, numvertices, options, declaration, device, mesh);
1056 }
1057
1058 HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height,
1059                              FLOAT depth, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1060 {
1061     FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device, width, height, depth, mesh, adjacency);
1062
1063     return E_NOTIMPL;
1064 }
1065
1066 struct vertex
1067 {
1068     D3DXVECTOR3 position;
1069     D3DXVECTOR3 normal;
1070 };
1071
1072 typedef WORD face[3];
1073
1074 struct sincos_table
1075 {
1076     float *sin;
1077     float *cos;
1078 };
1079
1080 static void free_sincos_table(struct sincos_table *sincos_table)
1081 {
1082     HeapFree(GetProcessHeap(), 0, sincos_table->cos);
1083     HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1084 }
1085
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)
1088 {
1089     float angle;
1090     int i;
1091
1092     sincos_table->sin = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->sin));
1093     if (!sincos_table->sin)
1094     {
1095         return FALSE;
1096     }
1097     sincos_table->cos = HeapAlloc(GetProcessHeap(), 0, n * sizeof(*sincos_table->cos));
1098     if (!sincos_table->cos)
1099     {
1100         HeapFree(GetProcessHeap(), 0, sincos_table->sin);
1101         return FALSE;
1102     }
1103
1104     angle = angle_start;
1105     for (i = 0; i < n; i++)
1106     {
1107         sincos_table->sin[i] = sin(angle);
1108         sincos_table->cos[i] = cos(angle);
1109         angle += angle_step;
1110     }
1111
1112     return TRUE;
1113 }
1114
1115 static WORD vertex_index(UINT slices, int slice, int stack)
1116 {
1117     return stack*slices+slice+1;
1118 }
1119
1120 HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices,
1121                                 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1122 {
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;
1133
1134     TRACE("(%p, %f, %u, %u, %p, %p)\n", device, radius, slices, stacks, mesh, adjacency);
1135
1136     if (!device || radius < 0.0f || slices < 2 || stacks < 2 || !mesh)
1137     {
1138         return D3DERR_INVALIDCALL;
1139     }
1140
1141     if (adjacency)
1142     {
1143         FIXME("Case of adjacency != NULL not implemented.\n");
1144         return E_NOTIMPL;
1145     }
1146
1147     number_of_vertices = 2 + slices * (stacks-1);
1148     number_of_faces = 2 * slices + (stacks - 2) * (2 * slices);
1149
1150     hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1151                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &sphere);
1152     if (FAILED(hr))
1153     {
1154         return hr;
1155     }
1156
1157     hr = sphere->lpVtbl->LockVertexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1158     if (FAILED(hr))
1159     {
1160         sphere->lpVtbl->Release(sphere);
1161         return hr;
1162     }
1163
1164     hr = sphere->lpVtbl->LockIndexBuffer(sphere, D3DLOCK_DISCARD, (LPVOID *)&faces);
1165     if (FAILED(hr))
1166     {
1167         sphere->lpVtbl->UnlockVertexBuffer(sphere);
1168         sphere->lpVtbl->Release(sphere);
1169         return hr;
1170     }
1171
1172     /* phi = angle on xz plane wrt z axis */
1173     phi_step = -2 * M_PI / slices;
1174     phi_start = M_PI / 2;
1175
1176     if (!compute_sincos_table(&phi, phi_start, phi_step, slices))
1177     {
1178         sphere->lpVtbl->UnlockIndexBuffer(sphere);
1179         sphere->lpVtbl->UnlockVertexBuffer(sphere);
1180         sphere->lpVtbl->Release(sphere);
1181         return E_OUTOFMEMORY;
1182     }
1183
1184     /* theta = angle on xy plane wrt x axis */
1185     theta_step = M_PI / stacks;
1186     theta = theta_step;
1187
1188     vertex = 0;
1189     face = 0;
1190     stack = 0;
1191
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++;
1199
1200     for (stack = 0; stack < stacks - 1; stack++)
1201     {
1202         sin_theta = sin(theta);
1203         cos_theta = cos(theta);
1204
1205         for (slice = 0; slice < slices; slice++)
1206         {
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++;
1214
1215             if (slice > 0)
1216             {
1217                 if (stack == 0)
1218                 {
1219                     /* top stack is triangle fan */
1220                     faces[face][0] = 0;
1221                     faces[face][1] = slice + 1;
1222                     faces[face][2] = slice;
1223                     face++;
1224                 }
1225                 else
1226                 {
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++;
1232
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++;
1237                 }
1238             }
1239         }
1240
1241         theta += theta_step;
1242
1243         if (stack == 0)
1244         {
1245             faces[face][0] = 0;
1246             faces[face][1] = 1;
1247             faces[face][2] = slice;
1248             face++;
1249         }
1250         else
1251         {
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++;
1256
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++;
1261         }
1262     }
1263
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;
1270
1271     /* bottom stack is triangle fan */
1272     for (slice = 1; slice < slices; slice++)
1273     {
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++;
1278     }
1279
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;
1283
1284     free_sincos_table(&phi);
1285     sphere->lpVtbl->UnlockIndexBuffer(sphere);
1286     sphere->lpVtbl->UnlockVertexBuffer(sphere);
1287     *mesh = sphere;
1288
1289     return D3D_OK;
1290 }
1291
1292 HRESULT WINAPI D3DXCreateCylinder(LPDIRECT3DDEVICE9 device, FLOAT radius1, FLOAT radius2, FLOAT length, UINT slices,
1293                                   UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
1294 {
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;
1306
1307     TRACE("(%p, %f, %f, %f, %u, %u, %p, %p)\n", device, radius1, radius2, length, slices, stacks, mesh, adjacency);
1308
1309     if (device == NULL || radius1 < 0.0f || radius2 < 0.0f || length < 0.0f || slices < 2 || stacks < 1 || mesh == NULL)
1310     {
1311         return D3DERR_INVALIDCALL;
1312     }
1313
1314     if (adjacency)
1315     {
1316         FIXME("Case of adjacency != NULL not implemented.\n");
1317         return E_NOTIMPL;
1318     }
1319
1320     number_of_vertices = 2 + (slices * (3 + stacks));
1321     number_of_faces = 2 * slices + stacks * (2 * slices);
1322
1323     hr = D3DXCreateMeshFVF(number_of_faces, number_of_vertices, D3DXMESH_MANAGED,
1324                            D3DFVF_XYZ | D3DFVF_NORMAL, device, &cylinder);
1325     if (FAILED(hr))
1326     {
1327         return hr;
1328     }
1329
1330     hr = cylinder->lpVtbl->LockVertexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&vertices);
1331     if (FAILED(hr))
1332     {
1333         cylinder->lpVtbl->Release(cylinder);
1334         return hr;
1335     }
1336
1337     hr = cylinder->lpVtbl->LockIndexBuffer(cylinder, D3DLOCK_DISCARD, (LPVOID *)&faces);
1338     if (FAILED(hr))
1339     {
1340         cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1341         cylinder->lpVtbl->Release(cylinder);
1342         return hr;
1343     }
1344
1345     /* theta = angle on xy plane wrt x axis */
1346     theta_step = -2 * M_PI / slices;
1347     theta_start = M_PI / 2;
1348
1349     if (!compute_sincos_table(&theta, theta_start, theta_step, slices))
1350     {
1351         cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1352         cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1353         cylinder->lpVtbl->Release(cylinder);
1354         return E_OUTOFMEMORY;
1355     }
1356
1357     vertex = 0;
1358     face = 0;
1359     stack = 0;
1360
1361     delta_radius = radius1 - radius2;
1362     radius = radius1;
1363     radius_step = delta_radius / stacks;
1364
1365     z = -length / 2;
1366     z_step = length / stacks;
1367     z_normal = delta_radius / length;
1368     if (isnan(z_normal))
1369     {
1370         z_normal = 0.0f;
1371     }
1372
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;
1379
1380     for (slice = 0; slice < slices; slice++, vertex++)
1381     {
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;
1388
1389         if (slice > 0)
1390         {
1391             faces[face][0] = 0;
1392             faces[face][1] = slice;
1393             faces[face++][2] = slice + 1;
1394         }
1395     }
1396
1397     faces[face][0] = 0;
1398     faces[face][1] = slice;
1399     faces[face++][2] = 1;
1400
1401     for (stack = 1; stack <= stacks+1; stack++)
1402     {
1403         for (slice = 0; slice < slices; slice++, vertex++)
1404         {
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;
1412
1413             if (stack > 1 && slice > 0)
1414             {
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);
1418
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);
1422             }
1423         }
1424
1425         if (stack > 1)
1426         {
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);
1430
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);
1434         }
1435
1436         if (stack < stacks + 1)
1437         {
1438             z += z_step;
1439             radius -= radius_step;
1440         }
1441     }
1442
1443     for (slice = 0; slice < slices; slice++, vertex++)
1444     {
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;
1451
1452         if (slice > 0)
1453         {
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);
1457         }
1458     }
1459
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;
1466
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);
1470
1471     free_sincos_table(&theta);
1472     cylinder->lpVtbl->UnlockIndexBuffer(cylinder);
1473     cylinder->lpVtbl->UnlockVertexBuffer(cylinder);
1474     *mesh = cylinder;
1475
1476     return D3D_OK;
1477 }
1478
1479 HRESULT WINAPI D3DXCreateTeapot(LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh, LPD3DXBUFFER* adjacency)
1480 {
1481     FIXME("(%p, %p, %p): stub\n", device, mesh, adjacency);
1482
1483     return E_NOTIMPL;
1484 }