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