]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/mathlib/mathlib.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / libs / mathlib / mathlib.c
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 // mathlib.c -- math primitives\r
23 #include "mathlib.h"\r
24 // we use memcpy and memset\r
25 #include <memory.h>\r
26 \r
27 vec3_t vec3_origin = {0.0f,0.0f,0.0f};\r
28 \r
29 /*\r
30 ================\r
31 MakeNormalVectors\r
32 \r
33 Given a normalized forward vector, create two\r
34 other perpendicular vectors\r
35 ================\r
36 */\r
37 void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)\r
38 {\r
39         float           d;\r
40 \r
41         // this rotate and negate guarantees a vector\r
42         // not colinear with the original\r
43         right[1] = -forward[0];\r
44         right[2] = forward[1];\r
45         right[0] = forward[2];\r
46 \r
47         d = DotProduct (right, forward);\r
48         VectorMA (right, -d, forward, right);\r
49         VectorNormalize (right, right);\r
50         CrossProduct (right, forward, up);\r
51 }\r
52 \r
53 vec_t VectorLength(vec3_t v)\r
54 {\r
55         int             i;\r
56         float   length;\r
57         \r
58         length = 0.0f;\r
59         for (i=0 ; i< 3 ; i++)\r
60                 length += v[i]*v[i];\r
61         length = (float)sqrt (length);\r
62 \r
63         return length;\r
64 }\r
65 \r
66 qboolean VectorCompare (vec3_t v1, vec3_t v2)\r
67 {\r
68         int             i;\r
69         \r
70         for (i=0 ; i<3 ; i++)\r
71                 if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)\r
72                         return qfalse;\r
73                         \r
74         return qtrue;\r
75 }\r
76 \r
77 /*\r
78 // FIXME TTimo this implementation has to be particular to radiant\r
79 //   through another name I'd say\r
80 vec_t Q_rint (vec_t in)\r
81 {\r
82   if (g_PrefsDlg.m_bNoClamp)\r
83     return in;\r
84   else\r
85     return (float)floor (in + 0.5);\r
86 }\r
87 */\r
88 \r
89 void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc )\r
90 {\r
91         vc[0] = va[0] + scale*vb[0];\r
92         vc[1] = va[1] + scale*vb[1];\r
93         vc[2] = va[2] + scale*vb[2];\r
94 }\r
95 \r
96 void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)\r
97 {\r
98         cross[0] = v1[1]*v2[2] - v1[2]*v2[1];\r
99         cross[1] = v1[2]*v2[0] - v1[0]*v2[2];\r
100         cross[2] = v1[0]*v2[1] - v1[1]*v2[0];\r
101 }\r
102 \r
103 vec_t _DotProduct (vec3_t v1, vec3_t v2)\r
104 {\r
105         return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];\r
106 }\r
107 \r
108 void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)\r
109 {\r
110         out[0] = va[0]-vb[0];\r
111         out[1] = va[1]-vb[1];\r
112         out[2] = va[2]-vb[2];\r
113 }\r
114 \r
115 void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)\r
116 {\r
117         out[0] = va[0]+vb[0];\r
118         out[1] = va[1]+vb[1];\r
119         out[2] = va[2]+vb[2];\r
120 }\r
121 \r
122 void _VectorCopy (vec3_t in, vec3_t out)\r
123 {\r
124         out[0] = in[0];\r
125         out[1] = in[1];\r
126         out[2] = in[2];\r
127 }\r
128 \r
129 vec_t VectorNormalize( const vec3_t in, vec3_t out ) {\r
130         vec_t   length, ilength;\r
131 \r
132         length = (vec_t)sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);\r
133         if (length == 0)\r
134         {\r
135                 VectorClear (out);\r
136                 return 0;\r
137         }\r
138 \r
139         ilength = 1.0f/length;\r
140         out[0] = in[0]*ilength;\r
141         out[1] = in[1]*ilength;\r
142         out[2] = in[2]*ilength;\r
143 \r
144         return length;\r
145 }\r
146 \r
147 vec_t ColorNormalize( const vec3_t in, vec3_t out ) {\r
148         float   max, scale;\r
149 \r
150         max = in[0];\r
151         if (in[1] > max)\r
152                 max = in[1];\r
153         if (in[2] > max)\r
154                 max = in[2];\r
155 \r
156         if (max == 0) {\r
157                 out[0] = out[1] = out[2] = 1.0;\r
158                 return 0;\r
159         }\r
160 \r
161         scale = 1.0f / max;\r
162 \r
163         VectorScale (in, scale, out);\r
164 \r
165         return max;\r
166 }\r
167 \r
168 void VectorInverse (vec3_t v)\r
169 {\r
170         v[0] = -v[0];\r
171         v[1] = -v[1];\r
172         v[2] = -v[2];\r
173 }\r
174 \r
175 /*\r
176 void VectorScale (vec3_t v, vec_t scale, vec3_t out)\r
177 {\r
178         out[0] = v[0] * scale;\r
179         out[1] = v[1] * scale;\r
180         out[2] = v[2] * scale;\r
181 }\r
182 */\r
183 \r
184 void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out)\r
185 {\r
186   vec3_t vWork, va;\r
187   int nIndex[3][2];\r
188   int i;\r
189 \r
190   VectorCopy(vIn, va);\r
191   VectorCopy(va, vWork);\r
192   nIndex[0][0] = 1; nIndex[0][1] = 2;\r
193   nIndex[1][0] = 2; nIndex[1][1] = 0;\r
194   nIndex[2][0] = 0; nIndex[2][1] = 1;\r
195 \r
196   for (i = 0; i < 3; i++)\r
197   {\r
198     if (vRotation[i] != 0)\r
199     {\r
200       float dAngle = vRotation[i] * Q_PI / 180.0f;\r
201             float c = (vec_t)cos(dAngle);\r
202       float s = (vec_t)sin(dAngle);\r
203       vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s;\r
204       vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c;\r
205     }\r
206     VectorCopy(vWork, va);\r
207   }\r
208   VectorCopy(vWork, out);\r
209 }\r
210 \r
211 void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out)\r
212 {\r
213   vec3_t vTemp, vTemp2;\r
214 \r
215   VectorSubtract(vIn, vOrigin, vTemp);\r
216   VectorRotate(vTemp, vRotation, vTemp2);\r
217   VectorAdd(vTemp2, vOrigin, out);\r
218 }\r
219 \r
220 void VectorPolar(vec3_t v, float radius, float theta, float phi)\r
221 {\r
222         v[0]=(float)(radius * cos(theta) * cos(phi));\r
223         v[1]=(float)(radius * sin(theta) * cos(phi));\r
224         v[2]=(float)(radius * sin(phi));\r
225 }\r
226 \r
227 void VectorSnap(vec3_t v)\r
228 {\r
229   int i;\r
230   for (i = 0; i < 3; i++)\r
231   {\r
232     v[i] = (vec_t)floor (v[i] + 0.5);\r
233   }\r
234 }\r
235 \r
236 void VectorISnap(vec3_t point, int snap)\r
237 {\r
238   int i;\r
239         for (i = 0 ;i < 3 ; i++)\r
240         {\r
241                 point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap;\r
242         }\r
243 }\r
244 \r
245 void VectorFSnap(vec3_t point, float snap)\r
246 {\r
247   int i;\r
248         for (i = 0 ;i < 3 ; i++)\r
249         {\r
250                 point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap;\r
251         }\r
252 }\r
253 \r
254 void _Vector5Add (vec5_t va, vec5_t vb, vec5_t out)\r
255 {\r
256         out[0] = va[0]+vb[0];\r
257         out[1] = va[1]+vb[1];\r
258         out[2] = va[2]+vb[2];\r
259         out[3] = va[3]+vb[3];\r
260         out[4] = va[4]+vb[4];\r
261 }\r
262 \r
263 void _Vector5Scale (vec5_t v, vec_t scale, vec5_t out)\r
264 {\r
265         out[0] = v[0] * scale;\r
266         out[1] = v[1] * scale;\r
267         out[2] = v[2] * scale;\r
268         out[3] = v[3] * scale;\r
269         out[4] = v[4] * scale;\r
270 }\r
271 \r
272 void _Vector53Copy (vec5_t in, vec3_t out)\r
273 {\r
274         out[0] = in[0];\r
275         out[1] = in[1];\r
276         out[2] = in[2];\r
277 }\r
278 \r
279 // NOTE: added these from Ritual's Q3Radiant\r
280 void ClearBounds (vec3_t mins, vec3_t maxs)\r
281 {\r
282         mins[0] = mins[1] = mins[2] = 99999;\r
283         maxs[0] = maxs[1] = maxs[2] = -99999;\r
284 }\r
285 \r
286 void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)\r
287 {\r
288         int             i;\r
289         vec_t   val;\r
290         \r
291         for (i=0 ; i<3 ; i++)\r
292         {\r
293                 val = v[i];\r
294                 if (val < mins[i])\r
295                         mins[i] = val;\r
296                 if (val > maxs[i])\r
297                         maxs[i] = val;\r
298         }\r
299 }\r
300 \r
301 #define PITCH                           0               // up / down\r
302 #define YAW                                     1               // left / right\r
303 #define ROLL                            2               // fall over\r
304 #ifndef M_PI\r
305 #define M_PI            3.14159265358979323846f // matches value in gcc v2 math.h\r
306 #endif\r
307 \r
308 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)\r
309 {\r
310         float           angle;\r
311         static float            sr, sp, sy, cr, cp, cy;\r
312         // static to help MS compiler fp bugs\r
313         \r
314         angle = angles[YAW] * (M_PI*2.0f / 360.0f);\r
315         sy = (vec_t)sin(angle);\r
316         cy = (vec_t)cos(angle);\r
317         angle = angles[PITCH] * (M_PI*2.0f / 360.0f);\r
318         sp = (vec_t)sin(angle);\r
319         cp = (vec_t)cos(angle);\r
320         angle = angles[ROLL] * (M_PI*2.0f / 360.0f);\r
321         sr = (vec_t)sin(angle);\r
322         cr = (vec_t)cos(angle);\r
323         \r
324         if (forward)\r
325         {\r
326                 forward[0] = cp*cy;\r
327                 forward[1] = cp*sy;\r
328                 forward[2] = -sp;\r
329         }\r
330         if (right)\r
331         {\r
332                 right[0] = -sr*sp*cy+cr*sy;\r
333                 right[1] = -sr*sp*sy-cr*cy;\r
334                 right[2] = -sr*cp;\r
335         }\r
336         if (up)\r
337         {\r
338                 up[0] = cr*sp*cy+sr*sy;\r
339                 up[1] = cr*sp*sy-sr*cy;\r
340                 up[2] = cr*cp;\r
341         }\r
342 }\r
343 \r
344 void VectorToAngles( vec3_t vec, vec3_t angles )\r
345 {\r
346         float forward;\r
347         float yaw, pitch;\r
348         \r
349         if ( ( vec[ 0 ] == 0 ) && ( vec[ 1 ] == 0 ) )\r
350         {\r
351                 yaw = 0;\r
352                 if ( vec[ 2 ] > 0 )\r
353                 {\r
354                         pitch = 90;\r
355                 }\r
356                 else\r
357                 {\r
358                         pitch = 270;\r
359                 }\r
360         }\r
361         else\r
362         {\r
363                 yaw = (vec_t)atan2( vec[ 1 ], vec[ 0 ] ) * 180 / M_PI;\r
364                 if ( yaw < 0 )\r
365                 {\r
366                         yaw += 360;\r
367                 }\r
368                 \r
369                 forward = ( float )sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] );\r
370                 pitch = (vec_t)atan2( vec[ 2 ], forward ) * 180 / M_PI;\r
371                 if ( pitch < 0 )\r
372                 {\r
373                         pitch += 360;\r
374                 }\r
375         }\r
376         \r
377         angles[ 0 ] = pitch;\r
378         angles[ 1 ] = yaw;\r
379         angles[ 2 ] = 0;\r
380 }\r
381 \r
382 /*\r
383 =====================\r
384 PlaneFromPoints\r
385 \r
386 Returns false if the triangle is degenrate.\r
387 The normal will point out of the clock for clockwise ordered points\r
388 =====================\r
389 */\r
390 qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) {\r
391         vec3_t  d1, d2;\r
392 \r
393         VectorSubtract( b, a, d1 );\r
394         VectorSubtract( c, a, d2 );\r
395         CrossProduct( d2, d1, plane );\r
396         if ( VectorNormalize( plane, plane ) == 0 ) {\r
397                 return qfalse;\r
398         }\r
399 \r
400         plane[3] = DotProduct( a, plane );\r
401         return qtrue;\r
402 }\r
403 \r
404 /*\r
405 ** NormalToLatLong\r
406 **\r
407 ** We use two byte encoded normals in some space critical applications.\r
408 ** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format\r
409 ** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format\r
410 **\r
411 */\r
412 void NormalToLatLong( const vec3_t normal, byte bytes[2] ) {\r
413         // check for singularities\r
414         if ( normal[0] == 0 && normal[1] == 0 ) {\r
415                 if ( normal[2] > 0 ) {\r
416                         bytes[0] = 0;\r
417                         bytes[1] = 0;           // lat = 0, long = 0\r
418                 } else {\r
419                         bytes[0] = 128;\r
420                         bytes[1] = 0;           // lat = 0, long = 128\r
421                 }\r
422         } else {\r
423                 int     a, b;\r
424 \r
425                 a = (int)( RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ) );\r
426                 a &= 0xff;\r
427 \r
428                 b = (int)( RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ) );\r
429                 b &= 0xff;\r
430 \r
431                 bytes[0] = b;   // longitude\r
432                 bytes[1] = a;   // lattitude\r
433         }\r
434 }\r
435 \r
436 /*\r
437 =================\r
438 PlaneTypeForNormal\r
439 =================\r
440 */\r
441 int     PlaneTypeForNormal (vec3_t normal) {\r
442         if (normal[0] == 1.0 || normal[0] == -1.0)\r
443                 return PLANE_X;\r
444         if (normal[1] == 1.0 || normal[1] == -1.0)\r
445                 return PLANE_Y;\r
446         if (normal[2] == 1.0 || normal[2] == -1.0)\r
447                 return PLANE_Z;\r
448         \r
449         return PLANE_NON_AXIAL;\r
450 }\r
451 \r
452 /*\r
453 ================\r
454 MatrixMultiply\r
455 ================\r
456 */\r
457 void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) {\r
458         out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +\r
459                                 in1[0][2] * in2[2][0];\r
460         out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +\r
461                                 in1[0][2] * in2[2][1];\r
462         out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +\r
463                                 in1[0][2] * in2[2][2];\r
464         out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +\r
465                                 in1[1][2] * in2[2][0];\r
466         out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +\r
467                                 in1[1][2] * in2[2][1];\r
468         out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +\r
469                                 in1[1][2] * in2[2][2];\r
470         out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +\r
471                                 in1[2][2] * in2[2][0];\r
472         out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +\r
473                                 in1[2][2] * in2[2][1];\r
474         out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +\r
475                                 in1[2][2] * in2[2][2];\r
476 }\r
477 \r
478 void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )\r
479 {\r
480         float d;\r
481         vec3_t n;\r
482         float inv_denom;\r
483 \r
484         inv_denom = 1.0F / DotProduct( normal, normal );\r
485 \r
486         d = DotProduct( normal, p ) * inv_denom;\r
487 \r
488         n[0] = normal[0] * inv_denom;\r
489         n[1] = normal[1] * inv_denom;\r
490         n[2] = normal[2] * inv_denom;\r
491 \r
492         dst[0] = p[0] - d * n[0];\r
493         dst[1] = p[1] - d * n[1];\r
494         dst[2] = p[2] - d * n[2];\r
495 }\r
496 \r
497 /*\r
498 ** assumes "src" is normalized\r
499 */\r
500 void PerpendicularVector( vec3_t dst, const vec3_t src )\r
501 {\r
502         int     pos;\r
503         int i;\r
504         vec_t minelem = 1.0F;\r
505         vec3_t tempvec;\r
506 \r
507         /*\r
508         ** find the smallest magnitude axially aligned vector\r
509         */\r
510         for ( pos = 0, i = 0; i < 3; i++ )\r
511         {\r
512                 if ( fabs( src[i] ) < minelem )\r
513                 {\r
514                         pos = i;\r
515                         minelem = (vec_t)fabs( src[i] );\r
516                 }\r
517         }\r
518         tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;\r
519         tempvec[pos] = 1.0F;\r
520 \r
521         /*\r
522         ** project the point onto the plane defined by src\r
523         */\r
524         ProjectPointOnPlane( dst, tempvec, src );\r
525 \r
526         /*\r
527         ** normalize the result\r
528         */\r
529         VectorNormalize( dst, dst );\r
530 }\r
531 \r
532 /*\r
533 ===============\r
534 RotatePointAroundVector\r
535 \r
536 This is not implemented very well...\r
537 ===============\r
538 */\r
539 void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,\r
540                                                          float degrees ) {\r
541         float   m[3][3];\r
542         float   im[3][3];\r
543         float   zrot[3][3];\r
544         float   tmpmat[3][3];\r
545         float   rot[3][3];\r
546         int     i;\r
547         vec3_t vr, vup, vf;\r
548         float   rad;\r
549 \r
550         vf[0] = dir[0];\r
551         vf[1] = dir[1];\r
552         vf[2] = dir[2];\r
553 \r
554         PerpendicularVector( vr, dir );\r
555         CrossProduct( vr, vf, vup );\r
556 \r
557         m[0][0] = vr[0];\r
558         m[1][0] = vr[1];\r
559         m[2][0] = vr[2];\r
560 \r
561         m[0][1] = vup[0];\r
562         m[1][1] = vup[1];\r
563         m[2][1] = vup[2];\r
564 \r
565         m[0][2] = vf[0];\r
566         m[1][2] = vf[1];\r
567         m[2][2] = vf[2];\r
568 \r
569         memcpy( im, m, sizeof( im ) );\r
570 \r
571         im[0][1] = m[1][0];\r
572         im[0][2] = m[2][0];\r
573         im[1][0] = m[0][1];\r
574         im[1][2] = m[2][1];\r
575         im[2][0] = m[0][2];\r
576         im[2][1] = m[1][2];\r
577 \r
578         memset( zrot, 0, sizeof( zrot ) );\r
579         zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;\r
580 \r
581         rad = DEG2RAD( degrees );\r
582         zrot[0][0] = (vec_t)cos( rad );\r
583         zrot[0][1] = (vec_t)sin( rad );\r
584         zrot[1][0] = (vec_t)-sin( rad );\r
585         zrot[1][1] = (vec_t)cos( rad );\r
586 \r
587         MatrixMultiply( m, zrot, tmpmat );\r
588         MatrixMultiply( tmpmat, im, rot );\r
589 \r
590         for ( i = 0; i < 3; i++ ) {\r
591                 dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];\r
592         }\r
593 }\r