]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - mathlib.c
make dedicated work again
[xonotic/darkplaces.git] / mathlib.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program 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.  
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // mathlib.c -- math primitives
21
22 #include <math.h>
23 #include "quakedef.h"
24
25 void Sys_Error (char *error, ...);
26
27 vec3_t vec3_origin = {0,0,0};
28 int nanmask = 255<<23;
29 float ixtable[4096];
30
31 /*-----------------------------------------------------------------*/
32
33 float m_bytenormals[NUMVERTEXNORMALS][3] =
34 {
35 {-0.525731, 0.000000, 0.850651}, {-0.442863, 0.238856, 0.864188}, 
36 {-0.295242, 0.000000, 0.955423}, {-0.309017, 0.500000, 0.809017}, 
37 {-0.162460, 0.262866, 0.951056}, {0.000000, 0.000000, 1.000000}, 
38 {0.000000, 0.850651, 0.525731}, {-0.147621, 0.716567, 0.681718}, 
39 {0.147621, 0.716567, 0.681718}, {0.000000, 0.525731, 0.850651}, 
40 {0.309017, 0.500000, 0.809017}, {0.525731, 0.000000, 0.850651}, 
41 {0.295242, 0.000000, 0.955423}, {0.442863, 0.238856, 0.864188}, 
42 {0.162460, 0.262866, 0.951056}, {-0.681718, 0.147621, 0.716567}, 
43 {-0.809017, 0.309017, 0.500000}, {-0.587785, 0.425325, 0.688191}, 
44 {-0.850651, 0.525731, 0.000000}, {-0.864188, 0.442863, 0.238856},
45 {-0.716567, 0.681718, 0.147621}, {-0.688191, 0.587785, 0.425325}, 
46 {-0.500000, 0.809017, 0.309017}, {-0.238856, 0.864188, 0.442863}, 
47 {-0.425325, 0.688191, 0.587785}, {-0.716567, 0.681718, -0.147621}, 
48 {-0.500000, 0.809017, -0.309017}, {-0.525731, 0.850651, 0.000000}, 
49 {0.000000, 0.850651, -0.525731}, {-0.238856, 0.864188, -0.442863}, 
50 {0.000000, 0.955423, -0.295242}, {-0.262866, 0.951056, -0.162460}, 
51 {0.000000, 1.000000, 0.000000}, {0.000000, 0.955423, 0.295242}, 
52 {-0.262866, 0.951056, 0.162460}, {0.238856, 0.864188, 0.442863}, 
53 {0.262866, 0.951056, 0.162460}, {0.500000, 0.809017, 0.309017}, 
54 {0.238856, 0.864188, -0.442863}, {0.262866, 0.951056, -0.162460}, 
55 {0.500000, 0.809017, -0.309017}, {0.850651, 0.525731, 0.000000}, 
56 {0.716567, 0.681718, 0.147621}, {0.716567, 0.681718, -0.147621}, 
57 {0.525731, 0.850651, 0.000000}, {0.425325, 0.688191, 0.587785}, 
58 {0.864188, 0.442863, 0.238856}, {0.688191, 0.587785, 0.425325}, 
59 {0.809017, 0.309017, 0.500000}, {0.681718, 0.147621, 0.716567}, 
60 {0.587785, 0.425325, 0.688191}, {0.955423, 0.295242, 0.000000}, 
61 {1.000000, 0.000000, 0.000000}, {0.951056, 0.162460, 0.262866}, 
62 {0.850651, -0.525731, 0.000000}, {0.955423, -0.295242, 0.000000}, 
63 {0.864188, -0.442863, 0.238856}, {0.951056, -0.162460, 0.262866}, 
64 {0.809017, -0.309017, 0.500000}, {0.681718, -0.147621, 0.716567},
65 {0.850651, 0.000000, 0.525731}, {0.864188, 0.442863, -0.238856}, 
66 {0.809017, 0.309017, -0.500000}, {0.951056, 0.162460, -0.262866}, 
67 {0.525731, 0.000000, -0.850651}, {0.681718, 0.147621, -0.716567}, 
68 {0.681718, -0.147621, -0.716567}, {0.850651, 0.000000, -0.525731},
69 {0.809017, -0.309017, -0.500000}, {0.864188, -0.442863, -0.238856}, 
70 {0.951056, -0.162460, -0.262866}, {0.147621, 0.716567, -0.681718}, 
71 {0.309017, 0.500000, -0.809017}, {0.425325, 0.688191, -0.587785}, 
72 {0.442863, 0.238856, -0.864188}, {0.587785, 0.425325, -0.688191}, 
73 {0.688191, 0.587785, -0.425325}, {-0.147621, 0.716567, -0.681718}, 
74 {-0.309017, 0.500000, -0.809017}, {0.000000, 0.525731, -0.850651}, 
75 {-0.525731, 0.000000, -0.850651}, {-0.442863, 0.238856, -0.864188}, 
76 {-0.295242, 0.000000, -0.955423}, {-0.162460, 0.262866, -0.951056}, 
77 {0.000000, 0.000000, -1.000000}, {0.295242, 0.000000, -0.955423}, 
78 {0.162460, 0.262866, -0.951056}, {-0.442863, -0.238856, -0.864188}, 
79 {-0.309017, -0.500000, -0.809017}, {-0.162460, -0.262866, -0.951056}, 
80 {0.000000, -0.850651, -0.525731}, {-0.147621, -0.716567, -0.681718}, 
81 {0.147621, -0.716567, -0.681718}, {0.000000, -0.525731, -0.850651}, 
82 {0.309017, -0.500000, -0.809017}, {0.442863, -0.238856, -0.864188}, 
83 {0.162460, -0.262866, -0.951056}, {0.238856, -0.864188, -0.442863}, 
84 {0.500000, -0.809017, -0.309017}, {0.425325, -0.688191, -0.587785}, 
85 {0.716567, -0.681718, -0.147621}, {0.688191, -0.587785, -0.425325}, 
86 {0.587785, -0.425325, -0.688191}, {0.000000, -0.955423, -0.295242},
87 {0.000000, -1.000000, 0.000000}, {0.262866, -0.951056, -0.162460}, 
88 {0.000000, -0.850651, 0.525731}, {0.000000, -0.955423, 0.295242}, 
89 {0.238856, -0.864188, 0.442863}, {0.262866, -0.951056, 0.162460}, 
90 {0.500000, -0.809017, 0.309017}, {0.716567, -0.681718, 0.147621}, 
91 {0.525731, -0.850651, 0.000000}, {-0.238856, -0.864188, -0.442863}, 
92 {-0.500000, -0.809017, -0.309017}, {-0.262866, -0.951056, -0.162460}, 
93 {-0.850651, -0.525731, 0.000000}, {-0.716567, -0.681718, -0.147621}, 
94 {-0.716567, -0.681718, 0.147621}, {-0.525731, -0.850651, 0.000000}, 
95 {-0.500000, -0.809017, 0.309017}, {-0.238856, -0.864188, 0.442863},
96 {-0.262866, -0.951056, 0.162460}, {-0.864188, -0.442863, 0.238856}, 
97 {-0.809017, -0.309017, 0.500000}, {-0.688191, -0.587785, 0.425325}, 
98 {-0.681718, -0.147621, 0.716567}, {-0.442863, -0.238856, 0.864188}, 
99 {-0.587785, -0.425325, 0.688191}, {-0.309017, -0.500000, 0.809017}, 
100 {-0.147621, -0.716567, 0.681718}, {-0.425325, -0.688191, 0.587785}, 
101 {-0.162460, -0.262866, 0.951056}, {0.442863, -0.238856, 0.864188}, 
102 {0.162460, -0.262866, 0.951056}, {0.309017, -0.500000, 0.809017}, 
103 {0.147621, -0.716567, 0.681718}, {0.000000, -0.525731, 0.850651}, 
104 {0.425325, -0.688191, 0.587785}, {0.587785, -0.425325, 0.688191}, 
105 {0.688191, -0.587785, 0.425325}, {-0.955423, 0.295242, 0.000000}, 
106 {-0.951056, 0.162460, 0.262866}, {-1.000000, 0.000000, 0.000000}, 
107 {-0.850651, 0.000000, 0.525731}, {-0.955423, -0.295242, 0.000000}, 
108 {-0.951056, -0.162460, 0.262866}, {-0.864188, 0.442863, -0.238856}, 
109 {-0.951056, 0.162460, -0.262866}, {-0.809017, 0.309017, -0.500000}, 
110 {-0.864188, -0.442863, -0.238856}, {-0.951056, -0.162460, -0.262866},
111 {-0.809017, -0.309017, -0.500000}, {-0.681718, 0.147621, -0.716567}, 
112 {-0.681718, -0.147621, -0.716567}, {-0.850651, 0.000000, -0.525731}, 
113 {-0.688191, 0.587785, -0.425325}, {-0.587785, 0.425325, -0.688191}, 
114 {-0.425325, 0.688191, -0.587785}, {-0.425325, -0.688191, -0.587785}, 
115 {-0.587785, -0.425325, -0.688191}, {-0.688191, -0.587785, -0.425325}, 
116 };
117
118 byte NormalToByte(vec3_t n)
119 {
120         int i, best;
121         float bestdistance, distance;
122
123         best = 0;
124         bestdistance = DotProduct (n, m_bytenormals[0]);
125         for (i = 1;i < NUMVERTEXNORMALS;i++)
126         {
127                 distance = DotProduct (n, m_bytenormals[i]);
128                 if (distance > bestdistance)
129                 {
130                         bestdistance = distance;
131                         best = i;
132                 }
133         }
134         return best;
135 }
136
137 // note: uses byte partly to force unsigned for the validity check
138 void ByteToNormal(byte num, vec3_t n)
139 {
140         if (num < NUMVERTEXNORMALS)
141                 VectorCopy(m_bytenormals[num], n)
142         else
143                 VectorClear(n) // FIXME: complain?
144 }
145
146 float Q_RSqrt(float number)
147 {
148         float y;
149
150         if (number == 0.0f)
151                 return 0.0f;
152
153         *((long *)&y) = 0x5f3759df - ((* (long *) &number) >> 1);
154         return y * (1.5f - (number * 0.5f * y * y));
155 }
156
157 void _VectorNormalizeFast(vec3_t v)
158 {
159         float y, number;
160
161         number = DotProduct(v, v);
162
163         if (number != 0.0)
164         {
165                 *((long *)&y) = 0x5f3759df - ((* (long *) &number) >> 1);
166                 y = y * (1.5f - (number * 0.5f * y * y));
167
168                 VectorScale(v, y, v);
169         }
170 }
171
172 #if 0
173 // LordHavoc: no longer used at all
174 void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
175 {
176 #if 0
177         // LordHavoc: the old way...
178         float d;
179         vec3_t n;
180         float inv_denom;
181
182         inv_denom = 1.0F / DotProduct( normal, normal );
183
184         d = DotProduct( normal, p ) * inv_denom;
185
186         n[0] = normal[0] * inv_denom;
187         n[1] = normal[1] * inv_denom;
188         n[2] = normal[2] * inv_denom;
189
190         dst[0] = p[0] - d * n[0];
191         dst[1] = p[1] - d * n[1];
192         dst[2] = p[2] - d * n[2];
193 #else
194         // LordHavoc: optimized to death and beyond
195         float d;
196
197         // LordHavoc: the normal is a unit vector by definition,
198         //            therefore inv_denom was pointless.
199         d = DotProduct(normal, p);
200         dst[0] = p[0] - d * normal[0];
201         dst[1] = p[1] - d * normal[1];
202         dst[2] = p[2] - d * normal[2];
203 #endif
204 }
205 #endif
206
207 // assumes "src" is normalized
208 void PerpendicularVector( vec3_t dst, const vec3_t src )
209 {
210 #if 0
211         // LordHavoc: the old way...
212         int     pos;
213         int i;
214         float minelem, d;
215         vec3_t tempvec;
216
217         // find the smallest magnitude axially aligned vector
218         minelem = 1.0F;
219         for ( pos = 0, i = 0; i < 3; i++ )
220         {
221                 if ( fabs( src[i] ) < minelem )
222                 {
223                         pos = i;
224                         minelem = fabs( src[i] );
225                 }
226         }
227         VectorClear(tempvec);
228         tempvec[pos] = 1.0F;
229
230         // project the point onto the plane defined by src
231         ProjectPointOnPlane( dst, tempvec, src );
232
233         // normalize the result
234         VectorNormalize(dst);
235 #else
236         // LordHavoc: optimized to death and beyond
237         int     pos;
238         float minelem;
239
240         if (src[0])
241         {
242                 dst[0] = 0;
243                 if (src[1])
244                 {
245                         dst[1] = 0;
246                         if (src[2])
247                         {
248                                 dst[2] = 0;
249                                 pos = 0;
250                                 minelem = fabs(src[0]);
251                                 if (fabs(src[1]) < minelem)
252                                 {
253                                         pos = 1;
254                                         minelem = fabs(src[1]);
255                                 }
256                                 if (fabs(src[2]) < minelem)
257                                         pos = 2;
258
259                                 dst[pos] = 1;
260                                 dst[0] -= src[pos] * src[0];
261                                 dst[1] -= src[pos] * src[1];
262                                 dst[2] -= src[pos] * src[2];
263
264                                 // normalize the result
265                                 VectorNormalize(dst);
266                         }
267                         else
268                                 dst[2] = 1;
269                 }
270                 else
271                 {
272                         dst[1] = 1;
273                         dst[2] = 0;
274                 }
275         }
276         else
277         {
278                 dst[0] = 1;
279                 dst[1] = 0;
280                 dst[2] = 0;
281         }
282 #endif
283 }
284
285
286 #ifdef _WIN32
287 #pragma optimize( "", off )
288 #endif
289
290
291 // LordHavoc: like AngleVectors, but taking a forward vector instead of angles, useful!
292 void VectorVectors(const vec3_t forward, vec3_t right, vec3_t up)
293 {
294         float d;
295
296         right[0] = forward[2];
297         right[1] = -forward[0];
298         right[2] = forward[1];
299
300         d = DotProduct(forward, right);
301         right[0] -= d * forward[0];
302         right[1] -= d * forward[1];
303         right[2] -= d * forward[2];
304         VectorNormalizeFast(right);
305         CrossProduct(right, forward, up);
306 }
307
308 void VectorVectorsDouble(const double *forward, double *right, double *up)
309 {
310         double d;
311
312         right[0] = forward[2];
313         right[1] = -forward[0];
314         right[2] = forward[1];
315
316         d = DotProduct(forward, right);
317         right[0] -= d * forward[0];
318         right[1] -= d * forward[1];
319         right[2] -= d * forward[2];
320         VectorNormalize(right);
321         CrossProduct(right, forward, up);
322 }
323
324 void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
325 {
326 #if 0
327         // LordHavoc: the old way, cryptic brute force...
328         float   m[3][3];
329         float   im[3][3];
330         float   zrot[3][3];
331         float   tmpmat[3][3];
332         float   rot[3][3];
333         int     i;
334         vec3_t vr, vup, vf;
335
336         vf[0] = dir[0];
337         vf[1] = dir[1];
338         vf[2] = dir[2];
339
340         PerpendicularVector( vr, dir );
341         CrossProduct( vr, vf, vup );
342
343         m[0][0] = vr[0];
344         m[1][0] = vr[1];
345         m[2][0] = vr[2];
346
347         m[0][1] = vup[0];
348         m[1][1] = vup[1];
349         m[2][1] = vup[2];
350
351         m[0][2] = vf[0];
352         m[1][2] = vf[1];
353         m[2][2] = vf[2];
354
355         memcpy( im, m, sizeof( im ) );
356
357         im[0][1] = m[1][0];
358         im[0][2] = m[2][0];
359         im[1][0] = m[0][1];
360         im[1][2] = m[2][1];
361         im[2][0] = m[0][2];
362         im[2][1] = m[1][2];
363
364         memset( zrot, 0, sizeof( zrot ) );
365         zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
366
367         zrot[0][0] = cos( DEG2RAD( degrees ) );
368         zrot[0][1] = sin( DEG2RAD( degrees ) );
369         zrot[1][0] = -sin( DEG2RAD( degrees ) );
370         zrot[1][1] = cos( DEG2RAD( degrees ) );
371
372         R_ConcatRotations( m, zrot, tmpmat );
373         R_ConcatRotations( tmpmat, im, rot );
374
375         for ( i = 0; i < 3; i++ )
376                 dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
377 #elif 0
378         // LordHavoc: on the path to unintelligible code...
379 //      float   m[3][3];
380 //      float   im[3][3];
381 //      float   zrot[3][3];
382         float   tmpmat[3][3];
383 //      float   rot[3][3];
384         float   angle, c, s;
385 //      int     i;
386         vec3_t vr, vu, vf;
387
388         angle = DEG2RAD(degrees);
389
390         c = cos(angle);
391         s = sin(angle);
392
393         vf[0] = dir[0];
394         vf[1] = dir[1];
395         vf[2] = dir[2];
396
397         PerpendicularVector(vr, dir);
398         CrossProduct(vr, vf, vu);
399
400 //      m   [0][0] = vr[0];m   [0][1] = vu[0];m   [0][2] = vf[0];
401 //      m   [1][0] = vr[1];m   [1][1] = vu[1];m   [1][2] = vf[1];
402 //      m   [2][0] = vr[2];m   [2][1] = vu[2];m   [2][2] = vf[2];
403 //      im  [0][0] = vr[0];im  [0][1] = vr[1];im  [0][2] = vr[2];
404 //      im  [1][0] = vu[0];im  [1][1] = vu[1];im  [1][2] = vu[2];
405 //      im  [2][0] = vf[0];im  [2][1] = vf[1];im  [2][2] = vf[2];
406 //      zrot[0][0] =     c;zrot[0][1] =     s;zrot[0][2] =     0;
407 //      zrot[1][0] =    -s;zrot[1][1] =     c;zrot[1][2] =     0;
408 //      zrot[2][0] =     0;zrot[2][1] =     0;zrot[2][2] =     1;
409
410 //      tmpmat[0][0] = m[0][0] * zrot[0][0] + m[0][1] * zrot[1][0] + m[0][2] * zrot[2][0];
411 //      tmpmat[0][1] = m[0][0] * zrot[0][1] + m[0][1] * zrot[1][1] + m[0][2] * zrot[2][1];
412 //      tmpmat[0][2] = m[0][0] * zrot[0][2] + m[0][1] * zrot[1][2] + m[0][2] * zrot[2][2];
413 //      tmpmat[1][0] = m[1][0] * zrot[0][0] + m[1][1] * zrot[1][0] + m[1][2] * zrot[2][0];
414 //      tmpmat[1][1] = m[1][0] * zrot[0][1] + m[1][1] * zrot[1][1] + m[1][2] * zrot[2][1];
415 //      tmpmat[1][2] = m[1][0] * zrot[0][2] + m[1][1] * zrot[1][2] + m[1][2] * zrot[2][2];
416 //      tmpmat[2][0] = m[2][0] * zrot[0][0] + m[2][1] * zrot[1][0] + m[2][2] * zrot[2][0];
417 //      tmpmat[2][1] = m[2][0] * zrot[0][1] + m[2][1] * zrot[1][1] + m[2][2] * zrot[2][1];
418 //      tmpmat[2][2] = m[2][0] * zrot[0][2] + m[2][1] * zrot[1][2] + m[2][2] * zrot[2][2];
419
420         tmpmat[0][0] = vr[0] *  c + vu[0] * -s;
421         tmpmat[0][1] = vr[0] *  s + vu[0] *  c;
422 //      tmpmat[0][2] =                           vf[0];
423         tmpmat[1][0] = vr[1] *  c + vu[1] * -s;
424         tmpmat[1][1] = vr[1] *  s + vu[1] *  c;
425 //      tmpmat[1][2] =                           vf[1];
426         tmpmat[2][0] = vr[2] *  c + vu[2] * -s;
427         tmpmat[2][1] = vr[2] *  s + vu[2] *  c;
428 //      tmpmat[2][2] =                           vf[2];
429
430 //      rot[0][0] = tmpmat[0][0] * vr[0] + tmpmat[0][1] * vu[0] + tmpmat[0][2] * vf[0];
431 //      rot[0][1] = tmpmat[0][0] * vr[1] + tmpmat[0][1] * vu[1] + tmpmat[0][2] * vf[1];
432 //      rot[0][2] = tmpmat[0][0] * vr[2] + tmpmat[0][1] * vu[2] + tmpmat[0][2] * vf[2];
433 //      rot[1][0] = tmpmat[1][0] * vr[0] + tmpmat[1][1] * vu[0] + tmpmat[1][2] * vf[0];
434 //      rot[1][1] = tmpmat[1][0] * vr[1] + tmpmat[1][1] * vu[1] + tmpmat[1][2] * vf[1];
435 //      rot[1][2] = tmpmat[1][0] * vr[2] + tmpmat[1][1] * vu[2] + tmpmat[1][2] * vf[2];
436 //      rot[2][0] = tmpmat[2][0] * vr[0] + tmpmat[2][1] * vu[0] + tmpmat[2][2] * vf[0];
437 //      rot[2][1] = tmpmat[2][0] * vr[1] + tmpmat[2][1] * vu[1] + tmpmat[2][2] * vf[1];
438 //      rot[2][2] = tmpmat[2][0] * vr[2] + tmpmat[2][1] * vu[2] + tmpmat[2][2] * vf[2];
439
440 //      rot[0][0] = tmpmat[0][0] * vr[0] + tmpmat[0][1] * vu[0] + vf[0] * vf[0];
441 //      rot[0][1] = tmpmat[0][0] * vr[1] + tmpmat[0][1] * vu[1] + vf[0] * vf[1];
442 //      rot[0][2] = tmpmat[0][0] * vr[2] + tmpmat[0][1] * vu[2] + vf[0] * vf[2];
443 //      rot[1][0] = tmpmat[1][0] * vr[0] + tmpmat[1][1] * vu[0] + vf[1] * vf[0];
444 //      rot[1][1] = tmpmat[1][0] * vr[1] + tmpmat[1][1] * vu[1] + vf[1] * vf[1];
445 //      rot[1][2] = tmpmat[1][0] * vr[2] + tmpmat[1][1] * vu[2] + vf[1] * vf[2];
446 //      rot[2][0] = tmpmat[2][0] * vr[0] + tmpmat[2][1] * vu[0] + vf[2] * vf[0];
447 //      rot[2][1] = tmpmat[2][0] * vr[1] + tmpmat[2][1] * vu[1] + vf[2] * vf[1];
448 //      rot[2][2] = tmpmat[2][0] * vr[2] + tmpmat[2][1] * vu[2] + vf[2] * vf[2];
449
450 //      dst[0] = rot[0][0] * point[0] + rot[0][1] * point[1] + rot[0][2] * point[2];
451 //      dst[1] = rot[1][0] * point[0] + rot[1][1] * point[1] + rot[1][2] * point[2];
452 //      dst[2] = rot[2][0] * point[0] + rot[2][1] * point[1] + rot[2][2] * point[2];
453
454         dst[0] = (tmpmat[0][0] * vr[0] + tmpmat[0][1] * vu[0] + vf[0] * vf[0]) * point[0]
455                + (tmpmat[0][0] * vr[1] + tmpmat[0][1] * vu[1] + vf[0] * vf[1]) * point[1]
456                + (tmpmat[0][0] * vr[2] + tmpmat[0][1] * vu[2] + vf[0] * vf[2]) * point[2];
457         dst[1] = (tmpmat[1][0] * vr[0] + tmpmat[1][1] * vu[0] + vf[1] * vf[0]) * point[0]
458                + (tmpmat[1][0] * vr[1] + tmpmat[1][1] * vu[1] + vf[1] * vf[1]) * point[1]
459                + (tmpmat[1][0] * vr[2] + tmpmat[1][1] * vu[2] + vf[1] * vf[2]) * point[2];
460         dst[2] = (tmpmat[2][0] * vr[0] + tmpmat[2][1] * vu[0] + vf[2] * vf[0]) * point[0]
461                + (tmpmat[2][0] * vr[1] + tmpmat[2][1] * vu[1] + vf[2] * vf[1]) * point[1]
462                + (tmpmat[2][0] * vr[2] + tmpmat[2][1] * vu[2] + vf[2] * vf[2]) * point[2];
463 #else
464         // LordHavoc: optimized to death and beyond, cryptic in an entirely new way
465         float   t0, t1;
466         float   angle, c, s;
467         vec3_t  vr, vu, vf;
468
469         angle = DEG2RAD(degrees);
470
471         c = cos(angle);
472         s = sin(angle);
473
474         vf[0] = dir[0];
475         vf[1] = dir[1];
476         vf[2] = dir[2];
477
478 //      PerpendicularVector(vr, dir);
479 //      CrossProduct(vr, vf, vu);
480         VectorVectors(vf, vr, vu);
481
482         t0 = vr[0] *  c + vu[0] * -s;
483         t1 = vr[0] *  s + vu[0] *  c;
484         dst[0] = (t0 * vr[0] + t1 * vu[0] + vf[0] * vf[0]) * point[0]
485                + (t0 * vr[1] + t1 * vu[1] + vf[0] * vf[1]) * point[1]
486                + (t0 * vr[2] + t1 * vu[2] + vf[0] * vf[2]) * point[2];
487
488         t0 = vr[1] *  c + vu[1] * -s;
489         t1 = vr[1] *  s + vu[1] *  c;
490         dst[1] = (t0 * vr[0] + t1 * vu[0] + vf[1] * vf[0]) * point[0]
491                + (t0 * vr[1] + t1 * vu[1] + vf[1] * vf[1]) * point[1]
492                + (t0 * vr[2] + t1 * vu[2] + vf[1] * vf[2]) * point[2];
493
494         t0 = vr[2] *  c + vu[2] * -s;
495         t1 = vr[2] *  s + vu[2] *  c;
496         dst[2] = (t0 * vr[0] + t1 * vu[0] + vf[2] * vf[0]) * point[0]
497                + (t0 * vr[1] + t1 * vu[1] + vf[2] * vf[1]) * point[1]
498                + (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2];
499 #endif
500 }
501
502 #ifdef _WIN32
503 #pragma optimize( "", on )
504 #endif
505
506 /*-----------------------------------------------------------------*/
507
508
509 // LordHavoc note 1:
510 // BoxOnPlaneSide did a switch on a 'signbits' value and had optimized
511 // assembly in an attempt to accelerate it further, very inefficient
512 // considering that signbits of the frustum planes only changed each
513 // frame, and the world planes changed only at load time.
514 // So, to optimize it further I took the obvious route of storing a function
515 // pointer in the plane struct itself, and shrunk each of the individual
516 // cases to a single return statement.
517 // LordHavoc note 2:
518 // realized axial cases would be a nice speedup for world geometry, although
519 // never useful for the frustum planes.
520 int BoxOnPlaneSideX (vec3_t emins, vec3_t emaxs, mplane_t *p) {return p->dist <= emins[0] ? 1 : (p->dist >= emaxs[0] ? 2 : 3);}
521 int BoxOnPlaneSideY (vec3_t emins, vec3_t emaxs, mplane_t *p) {return p->dist <= emins[1] ? 1 : (p->dist >= emaxs[1] ? 2 : 3);}
522 int BoxOnPlaneSideZ (vec3_t emins, vec3_t emaxs, mplane_t *p) {return p->dist <= emins[2] ? 1 : (p->dist >= emaxs[2] ? 2 : 3);}
523 int BoxOnPlaneSide0 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]) >= p->dist) | (((p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]) < p->dist) << 1));}
524 int BoxOnPlaneSide1 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]) >= p->dist) | (((p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]) < p->dist) << 1));}
525 int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]) >= p->dist) | (((p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]) < p->dist) << 1));}
526 int BoxOnPlaneSide3 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]) >= p->dist) | (((p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]) < p->dist) << 1));}
527 int BoxOnPlaneSide4 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]) >= p->dist) | (((p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]) < p->dist) << 1));}
528 int BoxOnPlaneSide5 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2]) >= p->dist) | (((p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2]) < p->dist) << 1));}
529 int BoxOnPlaneSide6 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]) >= p->dist) | (((p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]) < p->dist) << 1));}
530 int BoxOnPlaneSide7 (vec3_t emins, vec3_t emaxs, mplane_t *p) {return (((p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2]) >= p->dist) | (((p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2]) < p->dist) << 1));}
531
532 void BoxOnPlaneSideClassify(mplane_t *p)
533 {
534         switch(p->type)
535         {
536         case 0: // x axis
537                 p->BoxOnPlaneSideFunc = BoxOnPlaneSideX;
538                 break;
539         case 1: // y axis
540                 p->BoxOnPlaneSideFunc = BoxOnPlaneSideY;
541                 break;
542         case 2: // z axis
543                 p->BoxOnPlaneSideFunc = BoxOnPlaneSideZ;
544                 break;
545         default:
546                 if (p->normal[2] < 0) // 4
547                 {
548                         if (p->normal[1] < 0) // 2
549                         {
550                                 if (p->normal[0] < 0) // 1
551                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide7;
552                                 else
553                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide6;
554                         }
555                         else
556                         {
557                                 if (p->normal[0] < 0) // 1
558                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide5;
559                                 else
560                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide4;
561                         }
562                 }
563                 else
564                 {
565                         if (p->normal[1] < 0) // 2
566                         {
567                                 if (p->normal[0] < 0) // 1
568                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide3;
569                                 else
570                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide2;
571                         }
572                         else
573                         {
574                                 if (p->normal[0] < 0) // 1
575                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide1;
576                                 else
577                                         p->BoxOnPlaneSideFunc = BoxOnPlaneSide0;
578                         }
579                 }
580                 break;
581         }
582 }
583
584 void PlaneClassify(mplane_t *p)
585 {
586         if (p->normal[0] == 1)
587                 p->type = 0;
588         else if (p->normal[1] == 1)
589                 p->type = 1;
590         else if (p->normal[2] == 1)
591                 p->type = 2;
592         else
593                 p->type = 3;
594         BoxOnPlaneSideClassify(p);
595 }
596
597 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
598 {
599         double angle, sr, sp, sy, cr, cp, cy;
600
601         angle = angles[YAW] * (M_PI*2 / 360);
602         sy = sin(angle);
603         cy = cos(angle);
604         angle = angles[PITCH] * (M_PI*2 / 360);
605         sp = sin(angle);
606         cp = cos(angle);
607         if (forward)
608         {
609                 forward[0] = cp*cy;
610                 forward[1] = cp*sy;
611                 forward[2] = -sp;
612         }
613         if (right || up)
614         {
615                 angle = angles[ROLL] * (M_PI*2 / 360);
616                 sr = sin(angle);
617                 cr = cos(angle);
618                 if (right)
619                 {
620                         right[0] = -1*(sr*sp*cy+cr*-sy);
621                         right[1] = -1*(sr*sp*sy+cr*cy);
622                         right[2] = -1*(sr*cp);
623                 }
624                 if (up)
625                 {
626                         up[0] = (cr*sp*cy+-sr*-sy);
627                         up[1] = (cr*sp*sy+-sr*cy);
628                         up[2] = cr*cp;
629                 }
630         }
631 }
632
633 void AngleVectorsFLU (vec3_t angles, vec3_t forward, vec3_t left, vec3_t up)
634 {
635         double angle, sr, sp, sy, cr, cp, cy;
636
637         angle = angles[YAW] * (M_PI*2 / 360);
638         sy = sin(angle);
639         cy = cos(angle);
640         angle = angles[PITCH] * (M_PI*2 / 360);
641         sp = sin(angle);
642         cp = cos(angle);
643         if (forward)
644         {
645                 forward[0] = cp*cy;
646                 forward[1] = cp*sy;
647                 forward[2] = -sp;
648         }
649         if (left || up)
650         {
651                 angle = angles[ROLL] * (M_PI*2 / 360);
652                 sr = sin(angle);
653                 cr = cos(angle);
654                 if (left)
655                 {
656                         left[0] = sr*sp*cy+cr*-sy;
657                         left[1] = sr*sp*sy+cr*cy;
658                         left[2] = sr*cp;
659                 }
660                 if (up)
661                 {
662                         up[0] = cr*sp*cy+-sr*-sy;
663                         up[1] = cr*sp*sy+-sr*cy;
664                         up[2] = cr*cp;
665                 }
666         }
667 }
668
669 void AngleMatrix (vec3_t angles, vec3_t translate, vec_t matrix[][4])
670 {
671         double angle, sr, sp, sy, cr, cp, cy;
672
673         angle = angles[YAW] * (M_PI*2 / 360);
674         sy = sin(angle);
675         cy = cos(angle);
676         angle = angles[PITCH] * (M_PI*2 / 360);
677         sp = sin(angle);
678         cp = cos(angle);
679         angle = angles[ROLL] * (M_PI*2 / 360);
680         sr = sin(angle);
681         cr = cos(angle);
682         matrix[0][0] = cp*cy;
683         matrix[0][1] = sr*sp*cy+cr*-sy;
684         matrix[0][2] = cr*sp*cy+-sr*-sy;
685         matrix[0][3] = translate[0];
686         matrix[1][0] = cp*sy;
687         matrix[1][1] = sr*sp*sy+cr*cy;
688         matrix[1][2] = cr*sp*sy+-sr*cy;
689         matrix[1][3] = translate[1];
690         matrix[2][0] = -sp;
691         matrix[2][1] = sr*cp;
692         matrix[2][2] = cr*cp;
693         matrix[2][3] = translate[2];
694 }
695
696 int VectorCompare (vec3_t v1, vec3_t v2)
697 {
698         int             i;
699
700         for (i=0 ; i<3 ; i++)
701                 if (v1[i] != v2[i])
702                         return 0;
703
704         return 1;
705 }
706
707 void VectorMASlow (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
708 {
709         vecc[0] = veca[0] + scale*vecb[0];
710         vecc[1] = veca[1] + scale*vecb[1];
711         vecc[2] = veca[2] + scale*vecb[2];
712 }
713
714
715 vec_t _DotProduct (vec3_t v1, vec3_t v2)
716 {
717         return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
718 }
719
720 void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
721 {
722         out[0] = veca[0]-vecb[0];
723         out[1] = veca[1]-vecb[1];
724         out[2] = veca[2]-vecb[2];
725 }
726
727 void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
728 {
729         out[0] = veca[0]+vecb[0];
730         out[1] = veca[1]+vecb[1];
731         out[2] = veca[2]+vecb[2];
732 }
733
734 void _VectorCopy (vec3_t in, vec3_t out)
735 {
736         out[0] = in[0];
737         out[1] = in[1];
738         out[2] = in[2];
739 }
740
741 // LordHavoc: changed CrossProduct to a #define
742 /*
743 void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
744 {
745         cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
746         cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
747         cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
748 }
749 */
750
751 double sqrt(double x);
752
753 vec_t Length(vec3_t v)
754 {
755         int             i;
756         float   length;
757
758         length = 0;
759         for (i=0 ; i< 3 ; i++)
760                 length += v[i]*v[i];
761         length = sqrt (length);         // FIXME
762
763         return length;
764 }
765
766 /*
767 // LordHavoc: fixme: do more research on gcc assembly so that qftol_minushalf and result will not be considered unused
768 static double qftol_minushalf = -0.5;
769
770 int qftol(double v)
771 {
772         int result;
773 #ifdef _MSC_VER
774         __asm
775         {
776                 fld             v
777                 fadd    qftol_minushalf
778                 fistp   result
779         }
780 #else // gcc hopefully
781         asm("fldl v\n\tfaddl qftol_minushalf\n\tfistpl result");
782 #endif
783         return result;
784 }
785 */
786
787 // LordHavoc: renamed these to Length, and made the normal ones #define
788 float VectorNormalizeLength (vec3_t v)
789 {
790         float   length, ilength;
791
792         length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
793         length = sqrt (length);         // FIXME
794
795         if (length)
796         {
797                 ilength = 1/length;
798                 v[0] *= ilength;
799                 v[1] *= ilength;
800                 v[2] *= ilength;
801         }
802                 
803         return length;
804
805 }
806
807 float VectorNormalizeLength2 (vec3_t v, vec3_t dest) // LordHavoc: added to allow copying while doing the calculation...
808 {
809         float   length, ilength;
810
811         length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
812         length = sqrt (length);         // FIXME
813
814         if (length)
815         {
816                 ilength = 1/length;
817                 dest[0] = v[0] * ilength;
818                 dest[1] = v[1] * ilength;
819                 dest[2] = v[2] * ilength;
820         }
821         else
822                 dest[0] = dest[1] = dest[2] = 0;
823                 
824         return length;
825
826 }
827
828 void _VectorInverse (vec3_t v)
829 {
830         v[0] = -v[0];
831         v[1] = -v[1];
832         v[2] = -v[2];
833 }
834
835 void _VectorScale (vec3_t in, vec_t scale, vec3_t out)
836 {
837         out[0] = in[0]*scale;
838         out[1] = in[1]*scale;
839         out[2] = in[2]*scale;
840 }
841
842
843 int Q_log2(int val)
844 {
845         int answer=0;
846         while (val>>=1)
847                 answer++;
848         return answer;
849 }
850
851
852 /*
853 ================
854 R_ConcatRotations
855 ================
856 */
857 void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
858 {
859         out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
860         out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
861         out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
862         out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];
863         out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];
864         out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];
865         out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];
866         out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
867         out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
868 }
869
870
871 /*
872 ================
873 R_ConcatTransforms
874 ================
875 */
876 void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
877 {
878         out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];
879         out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];
880         out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];
881         out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3];
882         out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];
883         out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];
884         out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];
885         out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3];
886         out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];
887         out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];
888         out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];
889         out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];
890 }
891
892
893 /*
894 ===================
895 FloorDivMod
896
897 Returns mathematically correct (floor-based) quotient and remainder for
898 numer and denom, both of which should contain no fractional part. The
899 quotient must fit in 32 bits.
900 ====================
901 */
902
903 void FloorDivMod (double numer, double denom, int *quotient,
904                 int *rem)
905 {
906         int             q, r;
907         double  x;
908
909 #ifndef PARANOID
910         if (denom <= 0.0)
911                 Sys_Error ("FloorDivMod: bad denominator %d\n", denom);
912
913 //      if ((floor(numer) != numer) || (floor(denom) != denom))
914 //              Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n",
915 //                              numer, denom);
916 #endif
917
918         if (numer >= 0.0)
919         {
920
921                 x = floor(numer / denom);
922                 q = (int)x;
923                 r = (int)floor(numer - (x * denom));
924         }
925         else
926         {
927         //
928         // perform operations with positive values, and fix mod to make floor-based
929         //
930                 x = floor(-numer / denom);
931                 q = -(int)x;
932                 r = (int)floor(-numer - (x * denom));
933                 if (r != 0)
934                 {
935                         q--;
936                         r = (int)denom - r;
937                 }
938         }
939
940         *quotient = q;
941         *rem = r;
942 }
943
944
945 /*
946 ===================
947 GreatestCommonDivisor
948 ====================
949 */
950 int GreatestCommonDivisor (int i1, int i2)
951 {
952         if (i1 > i2)
953         {
954                 if (i2 == 0)
955                         return (i1);
956                 return GreatestCommonDivisor (i2, i1 % i2);
957         }
958         else
959         {
960                 if (i1 == 0)
961                         return (i2);
962                 return GreatestCommonDivisor (i1, i2 % i1);
963         }
964 }
965
966
967 void Mathlib_Init(void)
968 {
969         int a;
970
971         // LordHavoc: setup 1.0f / N table for quick recipricols of integers
972         ixtable[0] = 0;
973         for (a = 1;a < 4096;a++)
974                 ixtable[a] = 1.0f / a;
975 }