]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - libs/mathlib/mathlib.c
Importing code changes for q3map2 from Rambetter-math-fix-experiments branch
[xonotic/netradiant.git] / libs / mathlib / mathlib.c
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 // mathlib.c -- math primitives
23 #include "mathlib.h"
24 // we use memcpy and memset
25 #include <memory.h>
26
27 vec3_t vec3_origin = {0.0f,0.0f,0.0f};
28
29 /*
30 ================
31 VectorIsOnAxis
32 ================
33 */
34 qboolean VectorIsOnAxis(vec3_t v)
35 {
36         int     i, zeroComponentCount;
37
38         zeroComponentCount = 0;
39         for (i = 0; i < 3; i++)
40         {
41                 if (v[i] == 0.0)
42                 {
43                         zeroComponentCount++;
44                 }
45         }
46
47         if (zeroComponentCount > 1)
48         {
49                 // The zero vector will be on axis.
50                 return qtrue;
51         }
52
53         return qfalse;
54 }
55
56 /*
57 ================
58 VectorIsOnAxialPlane
59 ================
60 */
61 qboolean VectorIsOnAxialPlane(vec3_t v)
62 {
63         int     i;
64
65         for (i = 0; i < 3; i++)
66         {
67                 if (v[i] == 0.0)
68                 {
69                         // The zero vector will be on axial plane.
70                         return qtrue;
71                 }
72         }
73
74         return qfalse;
75 }
76
77 /*
78 ================
79 MakeNormalVectors
80
81 Given a normalized forward vector, create two
82 other perpendicular vectors
83 ================
84 */
85 void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up)
86 {
87         float           d;
88
89         // this rotate and negate guarantees a vector
90         // not colinear with the original
91         right[1] = -forward[0];
92         right[2] = forward[1];
93         right[0] = forward[2];
94
95         d = DotProduct (right, forward);
96         VectorMA (right, -d, forward, right);
97         VectorNormalize (right, right);
98         CrossProduct (right, forward, up);
99 }
100
101 vec_t VectorLength(vec3_t v)
102 {
103         int             i;
104         float   length;
105         
106         length = 0.0f;
107         for (i=0 ; i< 3 ; i++)
108                 length += v[i]*v[i];
109         length = (float)sqrt (length);
110
111         return length;
112 }
113
114 qboolean VectorCompare (vec3_t v1, vec3_t v2)
115 {
116         int             i;
117         
118         for (i=0 ; i<3 ; i++)
119                 if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON)
120                         return qfalse;
121                         
122         return qtrue;
123 }
124
125 /*
126 // FIXME TTimo this implementation has to be particular to radiant
127 //   through another name I'd say
128 vec_t Q_rint (vec_t in)
129 {
130   if (g_PrefsDlg.m_bNoClamp)
131     return in;
132   else
133     return (float)floor (in + 0.5);
134 }
135 */
136
137 void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc )
138 {
139         vc[0] = va[0] + scale*vb[0];
140         vc[1] = va[1] + scale*vb[1];
141         vc[2] = va[2] + scale*vb[2];
142 }
143
144 void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
145 {
146         cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
147         cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
148         cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
149 }
150
151 vec_t _DotProduct (vec3_t v1, vec3_t v2)
152 {
153         return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
154 }
155
156 void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out)
157 {
158         out[0] = va[0]-vb[0];
159         out[1] = va[1]-vb[1];
160         out[2] = va[2]-vb[2];
161 }
162
163 void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out)
164 {
165         out[0] = va[0]+vb[0];
166         out[1] = va[1]+vb[1];
167         out[2] = va[2]+vb[2];
168 }
169
170 void _VectorCopy (vec3_t in, vec3_t out)
171 {
172         out[0] = in[0];
173         out[1] = in[1];
174         out[2] = in[2];
175 }
176
177 vec_t VectorNormalize( const vec3_t in, vec3_t out ) {
178
179         // The sqrt() function takes double as an input and returns double as an
180         // output according the the man pages on Debian and on FreeBSD.  Therefore,
181         // I don't see a reason why using a double outright (instead of using the
182         // vec_accu_t alias for example) could possibly be frowned upon.
183
184         double  x, y, z, length;
185
186         x = (double) in[0];
187         y = (double) in[1];
188         z = (double) in[2];
189
190         length = sqrt((x * x) + (y * y) + (z * z));
191         if (length == 0)
192         {
193                 VectorClear (out);
194                 return 0;
195         }
196
197         out[0] = (vec_t) (x / length);
198         out[1] = (vec_t) (y / length);
199         out[2] = (vec_t) (z / length);
200
201         return (vec_t) length;
202 }
203
204 vec_t ColorNormalize( const vec3_t in, vec3_t out ) {
205         float   max, scale;
206
207         max = in[0];
208         if (in[1] > max)
209                 max = in[1];
210         if (in[2] > max)
211                 max = in[2];
212
213         if (max == 0) {
214                 out[0] = out[1] = out[2] = 1.0;
215                 return 0;
216         }
217
218         scale = 1.0f / max;
219
220         VectorScale (in, scale, out);
221
222         return max;
223 }
224
225 void VectorInverse (vec3_t v)
226 {
227         v[0] = -v[0];
228         v[1] = -v[1];
229         v[2] = -v[2];
230 }
231
232 /*
233 void VectorScale (vec3_t v, vec_t scale, vec3_t out)
234 {
235         out[0] = v[0] * scale;
236         out[1] = v[1] * scale;
237         out[2] = v[2] * scale;
238 }
239 */
240
241 void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out)
242 {
243   vec3_t vWork, va;
244   int nIndex[3][2];
245   int i;
246
247   VectorCopy(vIn, va);
248   VectorCopy(va, vWork);
249   nIndex[0][0] = 1; nIndex[0][1] = 2;
250   nIndex[1][0] = 2; nIndex[1][1] = 0;
251   nIndex[2][0] = 0; nIndex[2][1] = 1;
252
253   for (i = 0; i < 3; i++)
254   {
255     if (vRotation[i] != 0)
256     {
257       float dAngle = vRotation[i] * Q_PI / 180.0f;
258             float c = (vec_t)cos(dAngle);
259       float s = (vec_t)sin(dAngle);
260       vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s;
261       vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c;
262     }
263     VectorCopy(vWork, va);
264   }
265   VectorCopy(vWork, out);
266 }
267
268 void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out)
269 {
270   vec3_t vTemp, vTemp2;
271
272   VectorSubtract(vIn, vOrigin, vTemp);
273   VectorRotate(vTemp, vRotation, vTemp2);
274   VectorAdd(vTemp2, vOrigin, out);
275 }
276
277 void VectorPolar(vec3_t v, float radius, float theta, float phi)
278 {
279         v[0]=(float)(radius * cos(theta) * cos(phi));
280         v[1]=(float)(radius * sin(theta) * cos(phi));
281         v[2]=(float)(radius * sin(phi));
282 }
283
284 void VectorSnap(vec3_t v)
285 {
286   int i;
287   for (i = 0; i < 3; i++)
288   {
289     v[i] = (vec_t)floor (v[i] + 0.5);
290   }
291 }
292
293 void VectorISnap(vec3_t point, int snap)
294 {
295   int i;
296         for (i = 0 ;i < 3 ; i++)
297         {
298                 point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap;
299         }
300 }
301
302 void VectorFSnap(vec3_t point, float snap)
303 {
304   int i;
305         for (i = 0 ;i < 3 ; i++)
306         {
307                 point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap;
308         }
309 }
310
311 void _Vector5Add (vec5_t va, vec5_t vb, vec5_t out)
312 {
313         out[0] = va[0]+vb[0];
314         out[1] = va[1]+vb[1];
315         out[2] = va[2]+vb[2];
316         out[3] = va[3]+vb[3];
317         out[4] = va[4]+vb[4];
318 }
319
320 void _Vector5Scale (vec5_t v, vec_t scale, vec5_t out)
321 {
322         out[0] = v[0] * scale;
323         out[1] = v[1] * scale;
324         out[2] = v[2] * scale;
325         out[3] = v[3] * scale;
326         out[4] = v[4] * scale;
327 }
328
329 void _Vector53Copy (vec5_t in, vec3_t out)
330 {
331         out[0] = in[0];
332         out[1] = in[1];
333         out[2] = in[2];
334 }
335
336 // NOTE: added these from Ritual's Q3Radiant
337 void ClearBounds (vec3_t mins, vec3_t maxs)
338 {
339         mins[0] = mins[1] = mins[2] = 99999;
340         maxs[0] = maxs[1] = maxs[2] = -99999;
341 }
342
343 void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
344 {
345         int             i;
346         vec_t   val;
347         
348         for (i=0 ; i<3 ; i++)
349         {
350                 val = v[i];
351                 if (val < mins[i])
352                         mins[i] = val;
353                 if (val > maxs[i])
354                         maxs[i] = val;
355         }
356 }
357
358 #define PITCH                           0               // up / down
359 #define YAW                                     1               // left / right
360 #define ROLL                            2               // fall over
361 #ifndef M_PI
362 #define M_PI            3.14159265358979323846f // matches value in gcc v2 math.h
363 #endif
364
365 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
366 {
367         float           angle;
368         static float            sr, sp, sy, cr, cp, cy;
369         // static to help MS compiler fp bugs
370         
371         angle = angles[YAW] * (M_PI*2.0f / 360.0f);
372         sy = (vec_t)sin(angle);
373         cy = (vec_t)cos(angle);
374         angle = angles[PITCH] * (M_PI*2.0f / 360.0f);
375         sp = (vec_t)sin(angle);
376         cp = (vec_t)cos(angle);
377         angle = angles[ROLL] * (M_PI*2.0f / 360.0f);
378         sr = (vec_t)sin(angle);
379         cr = (vec_t)cos(angle);
380         
381         if (forward)
382         {
383                 forward[0] = cp*cy;
384                 forward[1] = cp*sy;
385                 forward[2] = -sp;
386         }
387         if (right)
388         {
389                 right[0] = -sr*sp*cy+cr*sy;
390                 right[1] = -sr*sp*sy-cr*cy;
391                 right[2] = -sr*cp;
392         }
393         if (up)
394         {
395                 up[0] = cr*sp*cy+sr*sy;
396                 up[1] = cr*sp*sy-sr*cy;
397                 up[2] = cr*cp;
398         }
399 }
400
401 void VectorToAngles( vec3_t vec, vec3_t angles )
402 {
403         float forward;
404         float yaw, pitch;
405         
406         if ( ( vec[ 0 ] == 0 ) && ( vec[ 1 ] == 0 ) )
407         {
408                 yaw = 0;
409                 if ( vec[ 2 ] > 0 )
410                 {
411                         pitch = 90;
412                 }
413                 else
414                 {
415                         pitch = 270;
416                 }
417         }
418         else
419         {
420                 yaw = (vec_t)atan2( vec[ 1 ], vec[ 0 ] ) * 180 / M_PI;
421                 if ( yaw < 0 )
422                 {
423                         yaw += 360;
424                 }
425                 
426                 forward = ( float )sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] );
427                 pitch = (vec_t)atan2( vec[ 2 ], forward ) * 180 / M_PI;
428                 if ( pitch < 0 )
429                 {
430                         pitch += 360;
431                 }
432         }
433         
434         angles[ 0 ] = pitch;
435         angles[ 1 ] = yaw;
436         angles[ 2 ] = 0;
437 }
438
439 /*
440 =====================
441 PlaneFromPoints
442
443 Returns false if the triangle is degenrate.
444 The normal will point out of the clock for clockwise ordered points
445 =====================
446 */
447 qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) {
448         vec3_t  d1, d2;
449
450         VectorSubtract( b, a, d1 );
451         VectorSubtract( c, a, d2 );
452         CrossProduct( d2, d1, plane );
453         if ( VectorNormalize( plane, plane ) == 0 ) {
454                 return qfalse;
455         }
456
457         plane[3] = DotProduct( a, plane );
458         return qtrue;
459 }
460
461 /*
462 ** NormalToLatLong
463 **
464 ** We use two byte encoded normals in some space critical applications.
465 ** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format
466 ** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format
467 **
468 */
469 void NormalToLatLong( const vec3_t normal, byte bytes[2] ) {
470         // check for singularities
471         if ( normal[0] == 0 && normal[1] == 0 ) {
472                 if ( normal[2] > 0 ) {
473                         bytes[0] = 0;
474                         bytes[1] = 0;           // lat = 0, long = 0
475                 } else {
476                         bytes[0] = 128;
477                         bytes[1] = 0;           // lat = 0, long = 128
478                 }
479         } else {
480                 int     a, b;
481
482                 a = (int)( RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ) );
483                 a &= 0xff;
484
485                 b = (int)( RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ) );
486                 b &= 0xff;
487
488                 bytes[0] = b;   // longitude
489                 bytes[1] = a;   // lattitude
490         }
491 }
492
493 /*
494 =================
495 PlaneTypeForNormal
496 =================
497 */
498 int     PlaneTypeForNormal (vec3_t normal) {
499         if (normal[0] == 1.0 || normal[0] == -1.0)
500                 return PLANE_X;
501         if (normal[1] == 1.0 || normal[1] == -1.0)
502                 return PLANE_Y;
503         if (normal[2] == 1.0 || normal[2] == -1.0)
504                 return PLANE_Z;
505         
506         return PLANE_NON_AXIAL;
507 }
508
509 /*
510 ================
511 MatrixMultiply
512 ================
513 */
514 void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) {
515         out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
516                                 in1[0][2] * in2[2][0];
517         out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
518                                 in1[0][2] * in2[2][1];
519         out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
520                                 in1[0][2] * in2[2][2];
521         out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
522                                 in1[1][2] * in2[2][0];
523         out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
524                                 in1[1][2] * in2[2][1];
525         out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
526                                 in1[1][2] * in2[2][2];
527         out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
528                                 in1[2][2] * in2[2][0];
529         out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
530                                 in1[2][2] * in2[2][1];
531         out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
532                                 in1[2][2] * in2[2][2];
533 }
534
535 void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
536 {
537         float d;
538         vec3_t n;
539         float inv_denom;
540
541         inv_denom = 1.0F / DotProduct( normal, normal );
542
543         d = DotProduct( normal, p ) * inv_denom;
544
545         n[0] = normal[0] * inv_denom;
546         n[1] = normal[1] * inv_denom;
547         n[2] = normal[2] * inv_denom;
548
549         dst[0] = p[0] - d * n[0];
550         dst[1] = p[1] - d * n[1];
551         dst[2] = p[2] - d * n[2];
552 }
553
554 /*
555 ** assumes "src" is normalized
556 */
557 void PerpendicularVector( vec3_t dst, const vec3_t src )
558 {
559         int     pos;
560         int i;
561         vec_t minelem = 1.0F;
562         vec3_t tempvec;
563
564         /*
565         ** find the smallest magnitude axially aligned vector
566         */
567         for ( pos = 0, i = 0; i < 3; i++ )
568         {
569                 if ( fabs( src[i] ) < minelem )
570                 {
571                         pos = i;
572                         minelem = (vec_t)fabs( src[i] );
573                 }
574         }
575         tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
576         tempvec[pos] = 1.0F;
577
578         /*
579         ** project the point onto the plane defined by src
580         */
581         ProjectPointOnPlane( dst, tempvec, src );
582
583         /*
584         ** normalize the result
585         */
586         VectorNormalize( dst, dst );
587 }
588
589 /*
590 ===============
591 RotatePointAroundVector
592
593 This is not implemented very well...
594 ===============
595 */
596 void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point,
597                                                          float degrees ) {
598         float   m[3][3];
599         float   im[3][3];
600         float   zrot[3][3];
601         float   tmpmat[3][3];
602         float   rot[3][3];
603         int     i;
604         vec3_t vr, vup, vf;
605         float   rad;
606
607         vf[0] = dir[0];
608         vf[1] = dir[1];
609         vf[2] = dir[2];
610
611         PerpendicularVector( vr, dir );
612         CrossProduct( vr, vf, vup );
613
614         m[0][0] = vr[0];
615         m[1][0] = vr[1];
616         m[2][0] = vr[2];
617
618         m[0][1] = vup[0];
619         m[1][1] = vup[1];
620         m[2][1] = vup[2];
621
622         m[0][2] = vf[0];
623         m[1][2] = vf[1];
624         m[2][2] = vf[2];
625
626         memcpy( im, m, sizeof( im ) );
627
628         im[0][1] = m[1][0];
629         im[0][2] = m[2][0];
630         im[1][0] = m[0][1];
631         im[1][2] = m[2][1];
632         im[2][0] = m[0][2];
633         im[2][1] = m[1][2];
634
635         memset( zrot, 0, sizeof( zrot ) );
636         zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
637
638         rad = DEG2RAD( degrees );
639         zrot[0][0] = (vec_t)cos( rad );
640         zrot[0][1] = (vec_t)sin( rad );
641         zrot[1][0] = (vec_t)-sin( rad );
642         zrot[1][1] = (vec_t)cos( rad );
643
644         MatrixMultiply( m, zrot, tmpmat );
645         MatrixMultiply( tmpmat, im, rot );
646
647         for ( i = 0; i < 3; i++ ) {
648                 dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
649         }
650 }
651
652
653 ////////////////////////////////////////////////////////////////////////////////
654 // Below is double-precision math stuff.  This was initially needed by the new
655 // "base winding" code in q3map2 brush processing in order to fix the famous
656 // "disappearing triangles" issue.  These definitions can be used wherever extra
657 // precision is needed.
658 ////////////////////////////////////////////////////////////////////////////////
659
660 /*
661 =================
662 VectorLengthAccu
663 =================
664 */
665 vec_accu_t VectorLengthAccu(const vec3_accu_t v)
666 {
667         return (vec_accu_t) sqrt((v[0] * v[0]) + (v[1] * v[1]) + (v[2] * v[2]));
668 }
669
670 /*
671 =================
672 DotProductAccu
673 =================
674 */
675 vec_accu_t DotProductAccu(const vec3_accu_t a, const vec3_accu_t b)
676 {
677         return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
678 }
679
680 /*
681 =================
682 VectorSubtractAccu
683 =================
684 */
685 void VectorSubtractAccu(const vec3_accu_t a, const vec3_accu_t b, vec3_accu_t out)
686 {
687         out[0] = a[0] - b[0];
688         out[1] = a[1] - b[1];
689         out[2] = a[2] - b[2];
690 }
691
692 /*
693 =================
694 VectorAddAccu
695 =================
696 */
697 void VectorAddAccu(const vec3_accu_t a, const vec3_accu_t b, vec3_accu_t out)
698 {
699         out[0] = a[0] + b[0];
700         out[1] = a[1] + b[1];
701         out[2] = a[2] + b[2];
702 }
703
704 /*
705 =================
706 VectorCopyAccu
707 =================
708 */
709 void VectorCopyAccu(const vec3_accu_t in, vec3_accu_t out)
710 {
711         out[0] = in[0];
712         out[1] = in[1];
713         out[2] = in[2];
714 }
715
716 /*
717 =================
718 VectorScaleAccu
719 =================
720 */
721 void VectorScaleAccu(const vec3_accu_t in, vec_accu_t scaleFactor, vec3_accu_t out)
722 {
723         out[0] = in[0] * scaleFactor;
724         out[1] = in[1] * scaleFactor;
725         out[2] = in[2] * scaleFactor;
726 }
727
728 /*
729 =================
730 CrossProductAccu
731 =================
732 */
733 void CrossProductAccu(const vec3_accu_t a, const vec3_accu_t b, vec3_accu_t out)
734 {
735         out[0] = (a[1] * b[2]) - (a[2] * b[1]);
736         out[1] = (a[2] * b[0]) - (a[0] * b[2]);
737         out[2] = (a[0] * b[1]) - (a[1] * b[0]);
738 }
739
740 /*
741 =================
742 Q_rintAccu
743 =================
744 */
745 vec_accu_t Q_rintAccu(vec_accu_t val)
746 {
747         return (vec_accu_t) floor(val + 0.5);
748 }
749
750 /*
751 =================
752 VectorCopyAccuToRegular
753 =================
754 */
755 void VectorCopyAccuToRegular(const vec3_accu_t in, vec3_t out)
756 {
757         out[0] = (vec_t) in[0];
758         out[1] = (vec_t) in[1];
759         out[2] = (vec_t) in[2];
760 }
761
762 /*
763 =================
764 VectorCopyRegularToAccu
765 =================
766 */
767 void VectorCopyRegularToAccu(const vec3_t in, vec3_accu_t out)
768 {
769         out[0] = (vec_accu_t) in[0];
770         out[1] = (vec_accu_t) in[1];
771         out[2] = (vec_accu_t) in[2];
772 }
773
774 /*
775 =================
776 VectorNormalizeAccu
777 =================
778 */
779 vec_accu_t VectorNormalizeAccu(const vec3_accu_t in, vec3_accu_t out)
780 {
781         // The sqrt() function takes double as an input and returns double as an
782         // output according the the man pages on Debian and on FreeBSD.  Therefore,
783         // I don't see a reason why using a double outright (instead of using the
784         // vec_accu_t alias for example) could possibly be frowned upon.
785
786         vec_accu_t      length;
787
788         length = (vec_accu_t) sqrt((in[0] * in[0]) + (in[1] * in[1]) + (in[2] * in[2]));
789         if (length == 0)
790         {
791                 VectorClear(out);
792                 return 0;
793         }
794
795         out[0] = in[0] / length;
796         out[1] = in[1] / length;
797         out[2] = in[2] / length;
798
799         return length;
800 }