wined3d: Handle the opcode specific control shift in the frontend rather than the...
[wine] / dlls / d3dx8 / mesh.c
1 /*
2  * Copyright 2008 David Adam
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wingdi.h"
24
25 #include "d3dx8_private.h"
26
27
28 BOOL WINAPI D3DXBoxBoundProbe(CONST D3DXVECTOR3 *pmin, CONST D3DXVECTOR3 *pmax, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
29
30 /* Algorithm taken from the article: An Efficient and Robust Ray-Box Intersection Algoritm
31 Amy Williams             University of Utah
32 Steve Barrus             University of Utah
33 R. Keith Morley          University of Utah
34 Peter Shirley            University of Utah
35
36 International Conference on Computer Graphics and Interactive Techniques  archive
37 ACM SIGGRAPH 2005 Courses
38 Los Angeles, California
39
40 This algorithm is free of patents or of copyrights, as confirmed by Peter Shirley himself.
41
42 Algorithm: Consider the box as the intersection of three slabs. Clip the ray
43 against each slab, if there's anything left of the ray after we're
44 done we've got an intersection of the ray with the box.
45 */
46
47 {
48     FLOAT div, tmin, tmax, tymin, tymax, tzmin, tzmax;
49
50     div = 1.0f / praydirection->x;
51     if ( div >= 0.0f )
52     {
53      tmin = ( pmin->x - prayposition->x ) * div;
54      tmax = ( pmax->x - prayposition->x ) * div;
55     }
56     else
57     {
58      tmin = ( pmax->x - prayposition->x ) * div;
59      tmax = ( pmin->x - prayposition->x ) * div;
60     }
61
62     if ( tmax < 0.0f ) return FALSE;
63
64     div = 1.0f / praydirection->y;
65     if ( div >= 0.0f )
66     {
67      tymin = ( pmin->y - prayposition->y ) * div;
68      tymax = ( pmax->y - prayposition->y ) * div;
69     }
70     else
71     {
72      tymin = ( pmax->y - prayposition->y ) * div;
73      tymax = ( pmin->y - prayposition->y ) * div;
74     }
75
76     if ( ( tymax < 0.0f ) || ( tmin > tymax ) || ( tymin > tmax ) ) return FALSE;
77
78     if ( tymin > tmin ) tmin = tymin;
79     if ( tymax < tmax ) tmax = tymax;
80
81     div = 1.0f / praydirection->z;
82     if ( div >= 0.0f )
83     {
84      tzmin = ( pmin->z - prayposition->z ) * div;
85      tzmax = ( pmax->z - prayposition->z ) * div;
86     }
87     else
88     {
89      tzmin = ( pmax->z - prayposition->z ) * div;
90      tzmax = ( pmin->z - prayposition->z ) * div;
91     }
92
93     if ( (tzmax < 0.0f ) || ( tmin > tzmax ) || ( tzmin > tmax ) ) return FALSE;
94
95     return TRUE;
96 }
97
98 HRESULT WINAPI D3DXComputeBoundingBox(PVOID ppointsFVF, DWORD numvertices, DWORD FVF, D3DXVECTOR3 *pmin, D3DXVECTOR3 *pmax)
99 {
100     D3DXVECTOR3 vec;
101     unsigned int i;
102
103     if( !ppointsFVF || !pmin || !pmax ) return D3DERR_INVALIDCALL;
104
105     *pmin = *(D3DXVECTOR3*)((char*)ppointsFVF);
106     *pmax = *pmin;
107
108 /* It looks like that D3DXComputeBoundingBox does not take in account the last vertex. */
109     for(i=0; i<numvertices-1; i++)
110     {
111         vec = *(D3DXVECTOR3*)((char*)ppointsFVF + D3DXGetFVFVertexSize(FVF) * i);
112
113         if ( vec.x < pmin->x ) pmin->x = vec.x;
114         if ( vec.x > pmax->x ) pmax->x = vec.x;
115
116         if ( vec.y < pmin->y ) pmin->y = vec.y;
117         if ( vec.y > pmax->y ) pmax->y = vec.y;
118
119         if ( vec.z < pmin->z ) pmin->z = vec.z;
120         if ( vec.z > pmax->z ) pmax->z = vec.z;
121     }
122
123     return D3D_OK;
124 }
125
126 HRESULT WINAPI D3DXComputeBoundingSphere(PVOID ppointsFVF, DWORD numvertices, DWORD FVF, D3DXVECTOR3 *pcenter, FLOAT *pradius)
127 {
128     D3DXVECTOR3 temp, temp1;
129     FLOAT d;
130     unsigned int i;
131
132     if( !ppointsFVF || !pcenter || !pradius ) return D3DERR_INVALIDCALL;
133
134     temp.x = 0.0f;
135     temp.y = 0.0f;
136     temp.z = 0.0f;
137     temp1 = temp;
138     d = 0.0f;
139     *pradius = 0.0f;
140
141     for(i=0; i<numvertices; i++)
142     {
143         D3DXVec3Add(&temp1, &temp, (D3DXVECTOR3*)((char*)ppointsFVF + D3DXGetFVFVertexSize(FVF) * i));
144         temp = temp1;
145     }
146
147     D3DXVec3Scale(pcenter, &temp, 1.0f/((FLOAT)numvertices));
148
149     for(i=0; i<numvertices; i++)
150     {
151         d = D3DXVec3Length(D3DXVec3Subtract(&temp, (D3DXVECTOR3*)((char*)ppointsFVF + D3DXGetFVFVertexSize(FVF) * i), pcenter));
152         if ( d > *pradius ) *pradius = d;
153     }
154     return D3D_OK;
155 }
156
157 static UINT Get_TexCoord_Size_From_FVF(DWORD FVF, int tex_num)
158 {
159     return (((((FVF) >> (16 + (2 * (tex_num)))) + 1) & 0x03) + 1);
160 }
161
162 UINT WINAPI D3DXGetFVFVertexSize(DWORD FVF)
163 {
164     DWORD size = 0;
165     UINT i;
166     UINT numTextures = (FVF & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
167
168     if (FVF & D3DFVF_NORMAL) size +=  sizeof(D3DXVECTOR3);
169     if (FVF & D3DFVF_DIFFUSE) size += sizeof(DWORD);
170     if (FVF & D3DFVF_SPECULAR) size += sizeof(DWORD);
171     if (FVF & D3DFVF_PSIZE) size += sizeof(DWORD);
172
173     switch (FVF & D3DFVF_POSITION_MASK)
174     {
175         case D3DFVF_XYZ:    size += sizeof(D3DXVECTOR3); break;
176         case D3DFVF_XYZRHW: size += 4 * sizeof(FLOAT); break;
177         case D3DFVF_XYZB1:  size += 4 * sizeof(FLOAT); break;
178         case D3DFVF_XYZB2:  size += 5 * sizeof(FLOAT); break;
179         case D3DFVF_XYZB3:  size += 6 * sizeof(FLOAT); break;
180         case D3DFVF_XYZB4:  size += 7 * sizeof(FLOAT); break;
181         case D3DFVF_XYZB5:  size += 8 * sizeof(FLOAT); break;
182     }
183
184     for (i = 0; i < numTextures; i++)
185     {
186         size += Get_TexCoord_Size_From_FVF(FVF, i) * sizeof(FLOAT);
187     }
188
189     return size;
190 }
191
192 BOOL CDECL D3DXIntersectTri(CONST D3DXVECTOR3 *p0, CONST D3DXVECTOR3 *p1, CONST D3DXVECTOR3 *p2, CONST D3DXVECTOR3 *praypos, CONST D3DXVECTOR3 *praydir, FLOAT *pu, FLOAT *pv, FLOAT *pdist)
193 {
194     D3DXMATRIX m;
195     D3DXVECTOR4 vec;
196
197     m.m[0][0] = p1->x - p0->x;
198     m.m[1][0] = p2->x - p0->x;
199     m.m[2][0] = -praydir->x;
200     m.m[3][0] = 0.0f;
201     m.m[0][1] = p1->y - p0->z;
202     m.m[1][1] = p2->y - p0->z;
203     m.m[2][1] = -praydir->y;
204     m.m[3][1] = 0.0f;
205     m.m[0][2] = p1->z - p0->z;
206     m.m[1][2] = p2->z - p0->z;
207     m.m[2][2] = -praydir->z;
208     m.m[3][2] = 0.0f;
209     m.m[0][3] = 0.0f;
210     m.m[1][3] = 0.0f;
211     m.m[2][3] = 0.0f;
212     m.m[3][3] = 1.0f;
213
214     vec.x = praypos->x - p0->x;
215     vec.y = praypos->y - p0->y;
216     vec.z = praypos->z - p0->z;
217     vec.w = 0.0f;
218
219     if ( D3DXMatrixInverse(&m, NULL, &m) )
220     {
221         D3DXVec4Transform(&vec, &vec, &m);
222         if ( (vec.x >= 0.0f) && (vec.y >= 0.0f) && (vec.x + vec.y <= 1.0f) && (vec.z >= 0.0f) )
223         {
224             *pu = vec.x;
225             *pv = vec.y;
226             *pdist = fabs( vec.z );
227             return TRUE;
228         }
229     }
230
231 return FALSE;
232 }
233
234 BOOL WINAPI D3DXSphereBoundProbe(CONST D3DXVECTOR3 *pcenter, FLOAT radius, CONST D3DXVECTOR3 *prayposition, CONST D3DXVECTOR3 *praydirection)
235 {
236     D3DXVECTOR3 difference;
237     FLOAT a, b, c, d;
238
239     a = D3DXVec3LengthSq(praydirection);
240     if (!D3DXVec3Subtract(&difference, prayposition, pcenter)) return FALSE;
241     b = D3DXVec3Dot(&difference, praydirection);
242     c = D3DXVec3LengthSq(&difference) - radius * radius;
243     d = b * b - a * c;
244
245     if ( ( d <= 0.0f ) || ( sqrt(d) <= b ) ) return FALSE;
246     return TRUE;
247 }