2 * Mesh operations specific to D3DX9.
4 * Copyright (C) 2005 Henri Verbeet
5 * Copyright (C) 2006 Ivan Gyurdiev
6 * Copyright (C) 2009 David Adam
7 * Copyright (C) 2010 Tony Wasserka
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
27 #define NONAMELESSUNION
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
35 /*************************************************************************
38 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
40 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
41 Amy Williams University of Utah
42 Steve Barrus University of Utah
43 R. Keith Morley University of Utah
44 Peter Shirley University of Utah
46 International Conference on Computer Graphics and Interactive Techniques archive
47 ACM SIGGRAPH 2005 Courses
48 Los Angeles, California
50 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
52 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
53 against each slab, if there's anything left of the ray after we're
54 done we've got an intersection of the ray with the box.
58 FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
60 div = 1.0f / praydirection->x;
63 tmin = ( pmin->x - prayposition->x ) * div;
64 tmax = ( pmax->x - prayposition->x ) * div;
68 tmin = ( pmax->x - prayposition->x ) * div;
69 tmax = ( pmin->x - prayposition->x ) * div;
72 if ( tmax < 0.0f ) return FALSE;
74 div = 1.0f / praydirection->y;
77 tymin = ( pmin->y - prayposition->y ) * div;
78 tymax = ( pmax->y - prayposition->y ) * div;
82 tymin = ( pmax->y - prayposition->y ) * div;
83 tymax = ( pmin->y - prayposition->y ) * div;
86 if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
88 if ( tymin > tmin ) tmin = tymin;
89 if ( tymax < tmax ) tmax = tymax;
91 div = 1.0f / praydirection->z;
94 tzmin = ( pmin->z - prayposition->z ) * div;
95 tzmax = ( pmax->z - prayposition->z ) * div;
99 tzmin = ( pmax->z - prayposition->z ) * div;
100 tzmax = ( pmin->z - prayposition->z ) * div;
103 if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
108 /*************************************************************************
109 * D3DXComputeBoundingBox
111 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
116 if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
118 *pmin = *pfirstposition;
121 for(i=0; i<numvertices; i++)
123 vec = *( (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i) );
125 if ( vec.x < pmin->x ) pmin->x = vec.x;
126 if ( vec.x > pmax->x ) pmax->x = vec.x;
128 if ( vec.y < pmin->y ) pmin->y = vec.y;
129 if ( vec.y > pmax->y ) pmax->y = vec.y;
131 if ( vec.z < pmin->z ) pmin->z = vec.z;
132 if ( vec.z > pmax->z ) pmax->z = vec.z;
138 /*************************************************************************
139 * D3DXComputeBoundingSphere
141 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
143 D3DXVECTOR3 temp, temp1;
147 if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
156 for(i=0; i<numvertices; i++)
158 D3DXVec3Add(&temp1, &temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i));
162 D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
164 for(i=0; i<numvertices; i++)
166 d = D3DXVec3Length(D3DXVec3Subtract(&temp, (const D3DXVECTOR3*)((const char*)pfirstposition + dwstride * i), pcenter));
167 if ( d > *pradius ) *pradius = d;
172 static const UINT d3dx_decltype_size[D3DDECLTYPE_UNUSED] =
174 /* D3DDECLTYPE_FLOAT1 */ 1 * 4,
175 /* D3DDECLTYPE_FLOAT2 */ 2 * 4,
176 /* D3DDECLTYPE_FLOAT3 */ 3 * 4,
177 /* D3DDECLTYPE_FLOAT4 */ 4 * 4,
178 /* D3DDECLTYPE_D3DCOLOR */ 4 * 1,
179 /* D3DDECLTYPE_UBYTE4 */ 4 * 1,
180 /* D3DDECLTYPE_SHORT2 */ 2 * 2,
181 /* D3DDECLTYPE_SHORT4 */ 4 * 2,
182 /* D3DDECLTYPE_UBYTE4N */ 4 * 1,
183 /* D3DDECLTYPE_SHORT2N */ 2 * 2,
184 /* D3DDECLTYPE_SHORT4N */ 4 * 2,
185 /* D3DDECLTYPE_USHORT2N */ 2 * 2,
186 /* D3DDECLTYPE_USHORT4N */ 4 * 2,
187 /* D3DDECLTYPE_UDEC3 */ 4, /* 3 * 10 bits + 2 padding */
188 /* D3DDECLTYPE_DEC3N */ 4,
189 /* D3DDECLTYPE_FLOAT16_2 */ 2 * 2,
190 /* D3DDECLTYPE_FLOAT16_4 */ 4 * 2,
193 static void append_decl_element(D3DVERTEXELEMENT9 *declaration, UINT *idx, UINT *offset,
194 D3DDECLTYPE type, D3DDECLUSAGE usage, UINT usage_idx)
196 declaration[*idx].Stream = 0;
197 declaration[*idx].Offset = *offset;
198 declaration[*idx].Type = type;
199 declaration[*idx].Method = D3DDECLMETHOD_DEFAULT;
200 declaration[*idx].Usage = usage;
201 declaration[*idx].UsageIndex = usage_idx;
203 *offset += d3dx_decltype_size[type];
207 /*************************************************************************
208 * D3DXDeclaratorFromFVF
210 HRESULT WINAPI D3DXDeclaratorFromFVF(DWORD fvf, D3DVERTEXELEMENT9 declaration[MAX_FVF_DECL_SIZE])
212 static const D3DVERTEXELEMENT9 end_element = D3DDECL_END();
213 DWORD tex_count = (fvf & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
214 unsigned int offset = 0;
215 unsigned int idx = 0;
218 TRACE("fvf %#x, declaration %p.\n", fvf, declaration);
220 if (fvf & D3DFVF_POSITION_MASK)
222 BOOL has_blend = (fvf & D3DFVF_XYZB5) >= D3DFVF_XYZB1;
223 DWORD blend_count = 1 + (((fvf & D3DFVF_XYZB5) - D3DFVF_XYZB1) >> 1);
224 BOOL has_blend_idx = (fvf & D3DFVF_LASTBETA_D3DCOLOR) || (fvf & D3DFVF_LASTBETA_UBYTE4);
226 if (has_blend_idx) --blend_count;
228 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZW
229 || (has_blend && blend_count > 4))
230 return D3DERR_INVALIDCALL;
232 if ((fvf & D3DFVF_POSITION_MASK) == D3DFVF_XYZRHW)
233 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_POSITIONT, 0);
235 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_POSITION, 0);
244 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_BLENDWEIGHT, 0);
247 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_BLENDWEIGHT, 0);
250 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_BLENDWEIGHT, 0);
253 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_BLENDWEIGHT, 0);
256 ERR("Invalid blend count %u.\n", blend_count);
262 if (fvf & D3DFVF_LASTBETA_UBYTE4)
263 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_UBYTE4, D3DDECLUSAGE_BLENDINDICES, 0);
264 else if (fvf & D3DFVF_LASTBETA_D3DCOLOR)
265 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_BLENDINDICES, 0);
270 if (fvf & D3DFVF_NORMAL)
271 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_NORMAL, 0);
272 if (fvf & D3DFVF_PSIZE)
273 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_PSIZE, 0);
274 if (fvf & D3DFVF_DIFFUSE)
275 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 0);
276 if (fvf & D3DFVF_SPECULAR)
277 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_D3DCOLOR, D3DDECLUSAGE_COLOR, 1);
279 for (i = 0; i < tex_count; ++i)
281 switch ((fvf >> (16 + 2 * i)) & 0x03)
283 case D3DFVF_TEXTUREFORMAT1:
284 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT1, D3DDECLUSAGE_TEXCOORD, i);
286 case D3DFVF_TEXTUREFORMAT2:
287 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT2, D3DDECLUSAGE_TEXCOORD, i);
289 case D3DFVF_TEXTUREFORMAT3:
290 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT3, D3DDECLUSAGE_TEXCOORD, i);
292 case D3DFVF_TEXTUREFORMAT4:
293 append_decl_element(declaration, &idx, &offset, D3DDECLTYPE_FLOAT4, D3DDECLUSAGE_TEXCOORD, i);
298 declaration[idx] = end_element;
303 /*************************************************************************
304 * D3DXFVFFromDeclarator
306 HRESULT WINAPI D3DXFVFFromDeclarator(const D3DVERTEXELEMENT9 *declaration, DWORD *fvf)
308 unsigned int i = 0, texture, offset;
310 TRACE("(%p, %p)\n", declaration, fvf);
313 if (declaration[0].Type == D3DDECLTYPE_FLOAT3 && declaration[0].Usage == D3DDECLUSAGE_POSITION)
315 if ((declaration[1].Type == D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
316 declaration[1].UsageIndex == 0) &&
317 (declaration[2].Type == D3DDECLTYPE_FLOAT1 && declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES &&
318 declaration[2].UsageIndex == 0))
320 return D3DERR_INVALIDCALL;
322 else if ((declaration[1].Type == D3DDECLTYPE_UBYTE4 || declaration[1].Type == D3DDECLTYPE_D3DCOLOR) &&
323 declaration[1].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[1].UsageIndex == 0)
325 if (declaration[1].Type == D3DDECLTYPE_UBYTE4)
327 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_UBYTE4;
331 *fvf |= D3DFVF_XYZB1 | D3DFVF_LASTBETA_D3DCOLOR;
335 else if (declaration[1].Type <= D3DDECLTYPE_FLOAT4 && declaration[1].Usage == D3DDECLUSAGE_BLENDWEIGHT &&
336 declaration[1].UsageIndex == 0)
338 if ((declaration[2].Type == D3DDECLTYPE_UBYTE4 || declaration[2].Type == D3DDECLTYPE_D3DCOLOR) &&
339 declaration[2].Usage == D3DDECLUSAGE_BLENDINDICES && declaration[2].UsageIndex == 0)
341 if (declaration[2].Type == D3DDECLTYPE_UBYTE4)
343 *fvf |= D3DFVF_LASTBETA_UBYTE4;
347 *fvf |= D3DFVF_LASTBETA_D3DCOLOR;
349 switch (declaration[1].Type)
351 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB2; break;
352 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB3; break;
353 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB4; break;
354 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB5; break;
360 switch (declaration[1].Type)
362 case D3DDECLTYPE_FLOAT1: *fvf |= D3DFVF_XYZB1; break;
363 case D3DDECLTYPE_FLOAT2: *fvf |= D3DFVF_XYZB2; break;
364 case D3DDECLTYPE_FLOAT3: *fvf |= D3DFVF_XYZB3; break;
365 case D3DDECLTYPE_FLOAT4: *fvf |= D3DFVF_XYZB4; break;
376 else if (declaration[0].Type == D3DDECLTYPE_FLOAT4 && declaration[0].Usage == D3DDECLUSAGE_POSITIONT &&
377 declaration[0].UsageIndex == 0)
379 *fvf |= D3DFVF_XYZRHW;
383 if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_NORMAL)
385 *fvf |= D3DFVF_NORMAL;
388 if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_PSIZE &&
389 declaration[i].UsageIndex == 0)
391 *fvf |= D3DFVF_PSIZE;
394 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
395 declaration[i].UsageIndex == 0)
397 *fvf |= D3DFVF_DIFFUSE;
400 if (declaration[i].Type == D3DDECLTYPE_D3DCOLOR && declaration[i].Usage == D3DDECLUSAGE_COLOR &&
401 declaration[i].UsageIndex == 1)
403 *fvf |= D3DFVF_SPECULAR;
407 for (texture = 0; texture < D3DDP_MAXTEXCOORD; i++, texture++)
409 if (declaration[i].Stream == 0xFF)
413 else if (declaration[i].Type == D3DDECLTYPE_FLOAT1 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
414 declaration[i].UsageIndex == texture)
416 *fvf |= D3DFVF_TEXCOORDSIZE1(declaration[i].UsageIndex);
418 else if (declaration[i].Type == D3DDECLTYPE_FLOAT2 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
419 declaration[i].UsageIndex == texture)
421 *fvf |= D3DFVF_TEXCOORDSIZE2(declaration[i].UsageIndex);
423 else if (declaration[i].Type == D3DDECLTYPE_FLOAT3 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
424 declaration[i].UsageIndex == texture)
426 *fvf |= D3DFVF_TEXCOORDSIZE3(declaration[i].UsageIndex);
428 else if (declaration[i].Type == D3DDECLTYPE_FLOAT4 && declaration[i].Usage == D3DDECLUSAGE_TEXCOORD &&
429 declaration[i].UsageIndex == texture)
431 *fvf |= D3DFVF_TEXCOORDSIZE4(declaration[i].UsageIndex);
435 return D3DERR_INVALIDCALL;
439 *fvf |= (texture << D3DFVF_TEXCOUNT_SHIFT);
441 for (offset = 0, i = 0; declaration[i].Stream != 0xFF;
442 offset += d3dx_decltype_size[declaration[i].Type], i++)
444 if (declaration[i].Offset != offset)
446 return D3DERR_INVALIDCALL;
453 /*************************************************************************
454 * D3DXGetFVFVertexSize
456 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
458 return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
461 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
465 UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
467 if (FVF & D3DFVF_NORMAL) size += sizeof(D3DXVECTOR3);
468 if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
469 if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
470 if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
472 switch (FVF & D3DFVF_POSITION_MASK)
474 case D3DFVF_XYZ: size += sizeof(D3DXVECTOR3); break;
475 case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
476 case D3DFVF_XYZB1: size += 4 * sizeof(FLOAT); break;
477 case D3DFVF_XYZB2: size += 5 * sizeof(FLOAT); break;
478 case D3DFVF_XYZB3: size += 6 * sizeof(FLOAT); break;
479 case D3DFVF_XYZB4: size += 7 * sizeof(FLOAT); break;
480 case D3DFVF_XYZB5: size += 8 * sizeof(FLOAT); break;
481 case D3DFVF_XYZW: size += 4 * sizeof(FLOAT); break;
484 for (i = 0; i < numTextures; i++)
486 size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
492 /*************************************************************************
493 * D3DXGetDeclVertexSize
495 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
497 const D3DVERTEXELEMENT9 *element;
500 TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
504 for (element = decl; element->Stream != 0xff; ++element)
508 if (element->Stream != stream_idx) continue;
510 if (element->Type >= sizeof(d3dx_decltype_size) / sizeof(*d3dx_decltype_size))
512 FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
516 type_size = d3dx_decltype_size[element->Type];
517 if (element->Offset + type_size > size) size = element->Offset + type_size;
523 /*************************************************************************
526 UINT WINAPI D3DXGetDeclLength(const D3DVERTEXELEMENT9 *decl)
528 const D3DVERTEXELEMENT9 *element;
530 TRACE("decl %p\n", decl);
532 /* null decl results in exception on Windows XP */
534 for (element = decl; element->Stream != 0xff; ++element);
536 return element - decl;
539 /*************************************************************************
542 BOOL WINAPI D3DXIntersectTri(CONST D3DXVECTOR3 *p0, CONST D3DXVECTOR3 *p1, CONST D3DXVECTOR3 *p2, CONST D3DXVECTOR3 *praypos, CONST D3DXVECTOR3 *praydir, FLOAT *pu, FLOAT *pv, FLOAT *pdist)
547 m.u.m[0][0] = p1->x - p0->x;
548 m.u.m[1][0] = p2->x - p0->x;
549 m.u.m[2][0] = -praydir->x;
551 m.u.m[0][1] = p1->y - p0->z;
552 m.u.m[1][1] = p2->y - p0->z;
553 m.u.m[2][1] = -praydir->y;
555 m.u.m[0][2] = p1->z - p0->z;
556 m.u.m[1][2] = p2->z - p0->z;
557 m.u.m[2][2] = -praydir->z;
564 vec.x = praypos->x - p0->x;
565 vec.y = praypos->y - p0->y;
566 vec.z = praypos->z - p0->z;
569 if ( D3DXMatrixInverse(&m, NULL, &m) )
571 D3DXVec4Transform(&vec, &vec, &m);
572 if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
576 *pdist = fabs( vec.z );
584 /*************************************************************************
585 * D3DXSphereBoundProbe
587 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
589 D3DXVECTOR3 difference;
592 a = D3DXVec3LengthSq(praydirection);
593 if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
594 b = D3DXVec3Dot(&difference, praydirection);
595 c = D3DXVec3LengthSq(&difference) - radius * radius;
598 if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
602 HRESULT WINAPI D3DXCreateMesh(DWORD numfaces, DWORD numvertices, DWORD options, CONST D3DVERTEXELEMENT9 *declaration,
603 LPDIRECT3DDEVICE9 device, LPD3DXMESH *mesh)
605 FIXME("(%d, %d, %d, %p, %p, %p): stub\n", numfaces, numvertices, options, declaration, device, mesh);
610 HRESULT WINAPI D3DXCreateBox(LPDIRECT3DDEVICE9 device, FLOAT width, FLOAT height,
611 FLOAT depth, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
613 FIXME("(%p, %f, %f, %f, %p, %p): stub\n", device, width, height, depth, mesh, adjacency);
618 HRESULT WINAPI D3DXCreateSphere(LPDIRECT3DDEVICE9 device, FLOAT radius, UINT slices,
619 UINT stacks, LPD3DXMESH* mesh, LPD3DXBUFFER* adjacency)
621 FIXME("(%p, %f, %d, %d, %p, %p): stub\n", device, radius, slices, stacks, mesh, adjacency);