d3dx9: Merge d3dx8 mesh into d3dx9.
[wine] / dlls / d3dx9_36 / mesh.c
1  /*
2  * Mesh operations specific to D3DX9.
3  *
4  * Copyright (C) 2009 David Adam
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23 #include "wine/debug.h"
24 #include "windef.h"
25 #include "wingdi.h"
26 #include "d3dx9.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3dx);
29
30 /*************************************************************************
31  * D3DXBoxBoundProbe
32  */
33 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
34
35 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
36 Amy Williams             University of Utah
37 Steve Barrus             University of Utah
38 R. Keith Morley          University of Utah
39 Peter Shirley            University of Utah
40
41 International Conference on Computer Graphics and Interactive Techniques  archive
42 ACM SIGGRAPH 2005 Courses
43 Los Angeles, California
44
45 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
46
47 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
48 against each slab, if there's anything left of the ray after we're
49 done we've got an intersection of the ray with the box.
50 */
51
52 {
53     FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
54
55     div = 1.0f / praydirection->x;
56     if ( div >= 0.0f )
57     {
58      tmin = ( pmin->x - prayposition->x ) * div;
59      tmax = ( pmax->x - prayposition->x ) * div;
60     }
61     else
62     {
63      tmin = ( pmax->x - prayposition->x ) * div;
64      tmax = ( pmin->x - prayposition->x ) * div;
65     }
66
67     if ( tmax < 0.0f ) return FALSE;
68
69     div = 1.0f / praydirection->y;
70     if ( div >= 0.0f )
71     {
72      tymin = ( pmin->y - prayposition->y ) * div;
73      tymax = ( pmax->y - prayposition->y ) * div;
74     }
75     else
76     {
77      tymin = ( pmax->y - prayposition->y ) * div;
78      tymax = ( pmin->y - prayposition->y ) * div;
79     }
80
81     if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
82
83     if ( tymin > tmin ) tmin = tymin;
84     if ( tymax < tmax ) tmax = tymax;
85
86     div = 1.0f / praydirection->z;
87     if ( div >= 0.0f )
88     {
89      tzmin = ( pmin->z - prayposition->z ) * div;
90      tzmax = ( pmax->z - prayposition->z ) * div;
91     }
92     else
93     {
94      tzmin = ( pmax->z - prayposition->z ) * div;
95      tzmax = ( pmin->z - prayposition->z ) * div;
96     }
97
98     if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
99
100     return TRUE;
101 }
102
103 /*************************************************************************
104  * D3DXComputeBoundingBox
105  */
106 HRESULT WINAPI D3DXComputeBoundingBox(CONST D3DXVECTOR3 *pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
107 {
108     D3DXVECTOR3 vec;
109     unsigned int i;
110
111     if( !pfirstposition || !pmin || !pmax ) return D3DERR_INVALIDCALL;
112
113     *pmin = *pfirstposition;
114     *pmax = *pmin;
115
116     for(i=0; i<numvertices; i++)
117     {
118         vec = *( (D3DXVECTOR3*)((char*)pfirstposition + dwstride * i) );
119
120         if ( vec.x < pmin->x ) pmin->x = vec.x;
121         if ( vec.x > pmax->x ) pmax->x = vec.x;
122
123         if ( vec.y < pmin->y ) pmin->y = vec.y;
124         if ( vec.y > pmax->y ) pmax->y = vec.y;
125
126         if ( vec.z < pmin->z ) pmin->z = vec.z;
127         if ( vec.z > pmax->z ) pmax->z = vec.z;
128     }
129
130     return D3D_OK;
131 }
132
133 /*************************************************************************
134  * D3DXComputeBoundingSphere
135  */
136 HRESULT WINAPI D3DXComputeBoundingSphere(CONST D3DXVECTOR3* pfirstposition, DWORD numvertices, DWORD dwstride, D3DXVECTOR3 *pcenter, FLOAT *pradius)
137 {
138     D3DXVECTOR3 temp, temp1;
139     FLOAT d;
140     unsigned int i;
141
142     if( !pfirstposition || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
143
144     temp.x = 0.0f;
145     temp.y = 0.0f;
146     temp.z = 0.0f;
147     temp1 = temp;
148     d = 0.0f;
149     *pradius = 0.0f;
150
151     for(i=0; i<numvertices; i++)
152     {
153         D3DXVec3Add(&temp1, &temp, (D3DXVECTOR3*)((char*)pfirstposition + dwstride * i));
154         temp = temp1;
155     }
156
157     D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
158
159     for(i=0; i<numvertices; i++)
160     {
161         d = D3DXVec3Length(D3DXVec3Subtract(&temp, (D3DXVECTOR3*)((char*)pfirstposition + dwstride * i), pcenter));
162         if ( d > *pradius ) *pradius = d;
163     }
164     return D3D_OK;
165 }
166
167 /*************************************************************************
168  * D3DXGetFVFVertexSize
169  */
170 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
171 {
172     return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
173 }
174
175 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
176 {
177     DWORD size = 0;
178     UINT i;
179     UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
180
181     if (FVF & D3DFVF_NORMAL) size +=  sizeof(D3DXVECTOR3);
182     if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
183     if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
184     if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
185
186     switch (FVF & D3DFVF_POSITION_MASK)
187     {
188         case D3DFVF_XYZ:    size += sizeof(D3DXVECTOR3); break;
189         case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
190         case D3DFVF_XYZB1:  size += 4 * sizeof(FLOAT); break;
191         case D3DFVF_XYZB2:  size += 5 * sizeof(FLOAT); break;
192         case D3DFVF_XYZB3:  size += 6 * sizeof(FLOAT); break;
193         case D3DFVF_XYZB4:  size += 7 * sizeof(FLOAT); break;
194         case D3DFVF_XYZB5:  size += 8 * sizeof(FLOAT); break;
195         case D3DFVF_XYZW:   size += 4 * sizeof(FLOAT); break;
196     }
197
198     for (i = 0; i < numTextures; i++)
199     {
200         size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
201     }
202
203     return size;
204 }
205
206 /*************************************************************************
207  * D3DXGetDeclVertexSize
208  */
209 UINT WINAPI D3DXGetDeclVertexSize(const D3DVERTEXELEMENT9 *decl, DWORD stream_idx)
210 {
211     const D3DVERTEXELEMENT9 *element;
212     UINT size = 0;
213
214     TRACE("decl %p, stream_idx %u\n", decl, stream_idx);
215
216     if (!decl) return 0;
217
218     for (element = decl; element->Stream != 0xff; ++element)
219     {
220         UINT type_size;
221
222         if (element->Stream != stream_idx) continue;
223
224         switch (element->Type)
225         {
226             case D3DDECLTYPE_FLOAT1: type_size = 1 * 4; break;
227             case D3DDECLTYPE_FLOAT2: type_size = 2 * 4; break;
228             case D3DDECLTYPE_FLOAT3: type_size = 3 * 4; break;
229             case D3DDECLTYPE_FLOAT4: type_size = 4 * 4; break;
230             case D3DDECLTYPE_D3DCOLOR: type_size = 4 * 1; break;
231             case D3DDECLTYPE_UBYTE4: type_size = 4 * 1; break;
232             case D3DDECLTYPE_SHORT2: type_size = 2 * 2; break;
233             case D3DDECLTYPE_SHORT4: type_size = 4 * 2; break;
234             case D3DDECLTYPE_UBYTE4N: type_size = 4 * 1; break;
235             case D3DDECLTYPE_SHORT2N: type_size = 2 * 2; break;
236             case D3DDECLTYPE_SHORT4N: type_size = 4 * 2; break;
237             case D3DDECLTYPE_USHORT2N: type_size = 2 * 2; break;
238             case D3DDECLTYPE_USHORT4N: type_size = 4 * 2; break;
239             case D3DDECLTYPE_UDEC3: type_size = 4; break; /* 3 * 10 bits + 2 padding */
240             case D3DDECLTYPE_DEC3N: type_size = 4; break;
241             case D3DDECLTYPE_FLOAT16_2: type_size = 2 * 2; break;
242             case D3DDECLTYPE_FLOAT16_4: type_size = 4 * 2; break;
243             default:
244                 FIXME("Unhandled element type %#x, size will be incorrect.\n", element->Type);
245                 type_size = 0;
246                 break;
247         }
248
249         if (element->Offset + type_size > size) size = element->Offset + type_size;
250     }
251
252     return size;
253 }
254
255 /*************************************************************************
256  * D3DXIntersectTri
257  */
258 BOOL WINAPI D3DXIntersectTri(CONST D3DXVECTOR3 *p0, CONST D3DXVECTOR3 *p1, CONST D3DXVECTOR3 *p2, CONST D3DXVECTOR3 *praypos, CONST D3DXVECTOR3 *praydir, FLOAT *pu, FLOAT *pv, FLOAT *pdist)
259 {
260     D3DXMATRIX m;
261     D3DXVECTOR4 vec;
262
263     m.m[0][0] = p1->x - p0->x;
264     m.m[1][0] = p2->x - p0->x;
265     m.m[2][0] = -praydir->x;
266     m.m[3][0] = 0.0f;
267     m.m[0][1] = p1->y - p0->z;
268     m.m[1][1] = p2->y - p0->z;
269     m.m[2][1] = -praydir->y;
270     m.m[3][1] = 0.0f;
271     m.m[0][2] = p1->z - p0->z;
272     m.m[1][2] = p2->z - p0->z;
273     m.m[2][2] = -praydir->z;
274     m.m[3][2] = 0.0f;
275     m.m[0][3] = 0.0f;
276     m.m[1][3] = 0.0f;
277     m.m[2][3] = 0.0f;
278     m.m[3][3] = 1.0f;
279
280     vec.x = praypos->x - p0->x;
281     vec.y = praypos->y - p0->y;
282     vec.z = praypos->z - p0->z;
283     vec.w = 0.0f;
284
285     if ( D3DXMatrixInverse(&m, NULL, &m) )
286     {
287         D3DXVec4Transform(&vec, &vec, &m);
288         if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
289         {
290             *pu = vec.x;
291             *pv = vec.y;
292             *pdist = fabs( vec.z );
293             return TRUE;
294         }
295     }
296
297     return FALSE;
298 }
299
300 /*************************************************************************
301  * D3DXSphereBoundProbe
302  */
303 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
304 {
305     D3DXVECTOR3 difference;
306     FLOAT a, b, c, d;
307
308     a = D3DXVec3LengthSq(praydirection);
309     if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
310     b = D3DXVec3Dot(&difference, praydirection);
311     c = D3DXVec3LengthSq(&difference) - radius * radius;
312     d = b * b - a * c;
313
314     if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
315     return TRUE;
316 }