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