1 /*
2 Copyright (C) 1996-2001 Id Software, Inc.
3 Copyright (C) 2002-2009 John Fitzgibbons and others
4 Copyright (C) 2007-2008 Kristian Duske
5 Copyright (C) 2010-2014 QuakeSpasm developers
6
7 This program is free software; you can redistribute it and/or
8 modify it under the terms of the GNU General Public License
9 as published by the Free Software Foundation; either version 2
10 of the License, or (at your option) any later version.
11
12 This program 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.
15
16 See the GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22 */
23 // mathlib.c -- math primitives
24
25 #include "quakedef.h"
26
27 vec3_t vec3_origin = {0,0,0};
28
29 /*-----------------------------------------------------------------*/
30
31
32 //#define DEG2RAD( a ) ( a * M_PI ) / 180.0F
33 #define DEG2RAD( a ) ( (a) * M_PI_DIV_180 ) //johnfitz
34 #define ARCSECS_PER_RIGHT_ANGLE 324000
35 #define ARRSECS_PER_DEGREE 3600.f
36
ProjectPointOnPlane(vec3_t dst,const vec3_t p,const vec3_t normal)37 void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
38 {
39 float d;
40 vec3_t n;
41 float inv_denom;
42
43 inv_denom = 1.0F / DotProduct( normal, normal );
44
45 d = DotProduct( normal, p ) * inv_denom;
46
47 n[0] = normal[0] * inv_denom;
48 n[1] = normal[1] * inv_denom;
49 n[2] = normal[2] * inv_denom;
50
51 dst[0] = p[0] - d * n[0];
52 dst[1] = p[1] - d * n[1];
53 dst[2] = p[2] - d * n[2];
54 }
55
56 /*
57 ** assumes "src" is normalized
58 */
PerpendicularVector(vec3_t dst,const vec3_t src)59 void PerpendicularVector( vec3_t dst, const vec3_t src )
60 {
61 int pos;
62 int i;
63 float minelem = 1.0F;
64 vec3_t tempvec;
65
66 /*
67 ** find the smallest magnitude axially aligned vector
68 */
69 for ( pos = 0, i = 0; i < 3; i++ )
70 {
71 if ( fabs( src[i] ) < minelem )
72 {
73 pos = i;
74 minelem = fabs( src[i] );
75 }
76 }
77 tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
78 tempvec[pos] = 1.0F;
79
80 /*
81 ** project the point onto the plane defined by src
82 */
83 ProjectPointOnPlane( dst, tempvec, src );
84
85 /*
86 ** normalize the result
87 */
88 VectorNormalize( dst );
89 }
90
91 //johnfitz -- removed RotatePointAroundVector() becuase it's no longer used and my compiler fucked it up anyway
92
93 //spike -- readded, because it is useful, and my version of gcc has never had a problem with it.
RotatePointAroundVector(vec3_t dst,const vec3_t dir,const vec3_t point,float degrees)94 void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
95 {
96 float m[3][3];
97 float im[3][3];
98 float zrot[3][3];
99 float tmpmat[3][3];
100 float rot[3][3];
101 int i;
102 vec3_t vr, vu, vf;
103
104 vf[0] = dir[0];
105 vf[1] = dir[1];
106 vf[2] = dir[2];
107
108 PerpendicularVector( vr, dir );
109 CrossProduct( vr, vf, vu );
110
111 m[0][0] = vr[0];
112 m[1][0] = vr[1];
113 m[2][0] = vr[2];
114
115 m[0][1] = vu[0];
116 m[1][1] = vu[1];
117 m[2][1] = vu[2];
118
119 m[0][2] = vf[0];
120 m[1][2] = vf[1];
121 m[2][2] = vf[2];
122
123 memcpy( im, m, sizeof( im ) );
124
125 im[0][1] = m[1][0];
126 im[0][2] = m[2][0];
127 im[1][0] = m[0][1];
128 im[1][2] = m[2][1];
129 im[2][0] = m[0][2];
130 im[2][1] = m[1][2];
131
132 memset( zrot, 0, sizeof( zrot ) );
133 zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
134
135 zrot[0][0] = cos( DEG2RAD( degrees ) );
136 zrot[0][1] = sin( DEG2RAD( degrees ) );
137 zrot[1][0] = -sin( DEG2RAD( degrees ) );
138 zrot[1][1] = cos( DEG2RAD( degrees ) );
139
140 R_ConcatRotations( m, zrot, tmpmat );
141 R_ConcatRotations( tmpmat, im, rot );
142
143 for ( i = 0; i < 3; i++ )
144 {
145 dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
146 }
147 }
148 /*-----------------------------------------------------------------*/
149
150
anglemod(float a)151 float anglemod(float a)
152 {
153 #if 0
154 if (a >= 0)
155 a -= 360*(int)(a/360);
156 else
157 a += 360*( 1 + (int)(-a/360) );
158 #endif
159 a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
160 return a;
161 }
162
163
164 /*
165 ==================
166 BoxOnPlaneSide
167
168 Returns 1, 2, or 1 + 2
169 ==================
170 */
BoxOnPlaneSide(vec3_t emins,vec3_t emaxs,mplane_t * p)171 int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, mplane_t *p)
172 {
173 float dist1, dist2;
174 int sides;
175
176 #if 0 // this is done by the BOX_ON_PLANE_SIDE macro before calling this
177 // function
178 // fast axial cases
179 if (p->type < 3)
180 {
181 if (p->dist <= emins[p->type])
182 return 1;
183 if (p->dist >= emaxs[p->type])
184 return 2;
185 return 3;
186 }
187 #endif
188
189 // general case
190 switch (p->signbits)
191 {
192 case 0:
193 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
194 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
195 break;
196 case 1:
197 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
198 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
199 break;
200 case 2:
201 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
202 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
203 break;
204 case 3:
205 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
206 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
207 break;
208 case 4:
209 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
210 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
211 break;
212 case 5:
213 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
214 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
215 break;
216 case 6:
217 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
218 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
219 break;
220 case 7:
221 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
222 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
223 break;
224 default:
225 dist1 = dist2 = 0; // shut up compiler
226 Sys_Error ("BoxOnPlaneSide: Bad signbits");
227 break;
228 }
229
230 #if 0
231 int i;
232 vec3_t corners[2];
233
234 for (i=0 ; i<3 ; i++)
235 {
236 if (plane->normal[i] < 0)
237 {
238 corners[0][i] = emins[i];
239 corners[1][i] = emaxs[i];
240 }
241 else
242 {
243 corners[1][i] = emins[i];
244 corners[0][i] = emaxs[i];
245 }
246 }
247 dist = DotProduct (plane->normal, corners[0]) - plane->dist;
248 dist2 = DotProduct (plane->normal, corners[1]) - plane->dist;
249 sides = 0;
250 if (dist1 >= 0)
251 sides = 1;
252 if (dist2 < 0)
253 sides |= 2;
254 #endif
255
256 sides = 0;
257 if (dist1 >= p->dist)
258 sides = 1;
259 if (dist2 < p->dist)
260 sides |= 2;
261
262 #ifdef PARANOID
263 if (sides == 0)
264 Sys_Error ("BoxOnPlaneSide: sides==0");
265 #endif
266
267 return sides;
268 }
269
270 //johnfitz -- the opposite of AngleVectors. this takes forward and generates pitch yaw roll
271 //Spike: take right and up vectors to properly set yaw and roll
VectorAngles(const vec3_t forward,float * up,vec3_t angles)272 void VectorAngles (const vec3_t forward, float *up, vec3_t angles)
273 {
274 if (forward[0] == 0 && forward[1] == 0)
275 { //either vertically up or down
276 if (forward[2] > 0)
277 {
278 angles[PITCH] = -90;
279 angles[YAW] = up ? atan2(-up[1], -up[0]) / M_PI_DIV_180: 0;
280 }
281 else
282 {
283 angles[PITCH] = 90;
284 angles[YAW] = up ? atan2(up[1], up[0]) / M_PI_DIV_180: 0;
285 }
286 angles[ROLL] = 0;
287 }
288 else
289 {
290 angles[PITCH] = -atan2(forward[2], sqrt(DotProduct2(forward,forward)));
291 angles[YAW] = atan2(forward[1], forward[0]);
292
293 if (up)
294 {
295 vec_t cp = cos(angles[PITCH]), sp = sin(angles[PITCH]);
296 vec_t cy = cos(angles[YAW]), sy = sin(angles[YAW]);
297 vec3_t tleft, tup;
298 tleft[0] = -sy;
299 tleft[1] = cy;
300 tleft[2] = 0;
301 tup[0] = sp*cy;
302 tup[1] = sp*sy;
303 tup[2] = cp;
304 angles[ROLL] = -atan2(DotProduct(up, tleft), DotProduct(up, tup)) / M_PI_DIV_180;
305 }
306 else angles[ROLL] = 0;
307
308 angles[PITCH] /= M_PI_DIV_180;
309 angles[YAW] /= M_PI_DIV_180;
310 }
311 }
312
AngleVectors(vec3_t angles,vec3_t forward,vec3_t right,vec3_t up)313 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
314 {
315 float angle;
316 float sr, sp, sy, cr, cp, cy;
317
318 angle = angles[YAW] * (M_PI*2 / 360);
319 sy = sin(angle);
320 cy = cos(angle);
321 angle = angles[PITCH] * (M_PI*2 / 360);
322 sp = sin(angle);
323 cp = cos(angle);
324 angle = angles[ROLL] * (M_PI*2 / 360);
325 sr = sin(angle);
326 cr = cos(angle);
327
328 forward[0] = cp*cy;
329 forward[1] = cp*sy;
330 forward[2] = -sp;
331 right[0] = (-1*sr*sp*cy+-1*cr*-sy);
332 right[1] = (-1*sr*sp*sy+-1*cr*cy);
333 right[2] = -1*sr*cp;
334 up[0] = (cr*sp*cy+-sr*-sy);
335 up[1] = (cr*sp*sy+-sr*cy);
336 up[2] = cr*cp;
337 }
338
VectorCompare(vec3_t v1,vec3_t v2)339 int VectorCompare (vec3_t v1, vec3_t v2)
340 {
341 int i;
342
343 for (i=0 ; i<3 ; i++)
344 if (v1[i] != v2[i])
345 return 0;
346
347 return 1;
348 }
349
VectorMA(vec3_t veca,float scale,vec3_t vecb,vec3_t vecc)350 void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
351 {
352 vecc[0] = veca[0] + scale*vecb[0];
353 vecc[1] = veca[1] + scale*vecb[1];
354 vecc[2] = veca[2] + scale*vecb[2];
355 }
356
357
_DotProduct(vec3_t v1,vec3_t v2)358 vec_t _DotProduct (vec3_t v1, vec3_t v2)
359 {
360 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
361 }
362
_VectorSubtract(vec3_t veca,vec3_t vecb,vec3_t out)363 void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
364 {
365 out[0] = veca[0]-vecb[0];
366 out[1] = veca[1]-vecb[1];
367 out[2] = veca[2]-vecb[2];
368 }
369
_VectorAdd(vec3_t veca,vec3_t vecb,vec3_t out)370 void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
371 {
372 out[0] = veca[0]+vecb[0];
373 out[1] = veca[1]+vecb[1];
374 out[2] = veca[2]+vecb[2];
375 }
376
_VectorCopy(vec3_t in,vec3_t out)377 void _VectorCopy (vec3_t in, vec3_t out)
378 {
379 out[0] = in[0];
380 out[1] = in[1];
381 out[2] = in[2];
382 }
383
CrossProduct(const vec3_t v1,const vec3_t v2,vec3_t cross)384 void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross)
385 {
386 cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
387 cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
388 cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
389 }
390
VectorLength(vec3_t v)391 vec_t VectorLength(vec3_t v)
392 {
393 return sqrt(DotProduct(v,v));
394 }
395
VectorNormalize(vec3_t v)396 float VectorNormalize (vec3_t v)
397 {
398 float length, ilength;
399
400 length = sqrt(DotProduct(v,v));
401
402 if (length)
403 {
404 ilength = 1/length;
405 v[0] *= ilength;
406 v[1] *= ilength;
407 v[2] *= ilength;
408 }
409
410 return length;
411
412 }
413
VectorInverse(vec3_t v)414 void VectorInverse (vec3_t v)
415 {
416 v[0] = -v[0];
417 v[1] = -v[1];
418 v[2] = -v[2];
419 }
420
VectorScale(vec3_t in,vec_t scale,vec3_t out)421 void VectorScale (vec3_t in, vec_t scale, vec3_t out)
422 {
423 out[0] = in[0]*scale;
424 out[1] = in[1]*scale;
425 out[2] = in[2]*scale;
426 }
427
428
Q_log2(int val)429 int Q_log2(int val)
430 {
431 int answer=0;
432 while (val>>=1)
433 answer++;
434 return answer;
435 }
436
Q_nextPow2(int val)437 int Q_nextPow2(int val)
438 {
439 val--;
440 val |= val >> 1;
441 val |= val >> 2;
442 val |= val >> 4;
443 val |= val >> 8;
444 val |= val >> 16;
445 val++;
446 return val;
447 }
448
449 /*
450 ================
451 R_ConcatRotations
452 ================
453 */
R_ConcatRotations(float in1[3][3],float in2[3][3],float out[3][3])454 void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
455 {
456 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
457 in1[0][2] * in2[2][0];
458 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
459 in1[0][2] * in2[2][1];
460 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
461 in1[0][2] * in2[2][2];
462 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
463 in1[1][2] * in2[2][0];
464 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
465 in1[1][2] * in2[2][1];
466 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
467 in1[1][2] * in2[2][2];
468 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
469 in1[2][2] * in2[2][0];
470 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
471 in1[2][2] * in2[2][1];
472 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
473 in1[2][2] * in2[2][2];
474 }
475
476
477 /*
478 ================
479 R_ConcatTransforms
480 ================
481 */
R_ConcatTransforms(float in1[3][4],float in2[3][4],float out[3][4])482 void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
483 {
484 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
485 in1[0][2] * in2[2][0];
486 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
487 in1[0][2] * in2[2][1];
488 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
489 in1[0][2] * in2[2][2];
490 out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
491 in1[0][2] * in2[2][3] + in1[0][3];
492 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
493 in1[1][2] * in2[2][0];
494 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
495 in1[1][2] * in2[2][1];
496 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
497 in1[1][2] * in2[2][2];
498 out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
499 in1[1][2] * in2[2][3] + in1[1][3];
500 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
501 in1[2][2] * in2[2][0];
502 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
503 in1[2][2] * in2[2][1];
504 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
505 in1[2][2] * in2[2][2];
506 out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
507 in1[2][2] * in2[2][3] + in1[2][3];
508 }
509
510
511 /*
512 ===================
513 FloorDivMod
514
515 Returns mathematically correct (floor-based) quotient and remainder for
516 numer and denom, both of which should contain no fractional part. The
517 quotient must fit in 32 bits.
518 ====================
519 */
520
FloorDivMod(double numer,double denom,int * quotient,int * rem)521 void FloorDivMod (double numer, double denom, int *quotient,
522 int *rem)
523 {
524 int q, r;
525 double x;
526
527 #ifndef PARANOID
528 if (denom <= 0.0)
529 Sys_Error ("FloorDivMod: bad denominator %f\n", denom);
530
531 // if ((floor(numer) != numer) || (floor(denom) != denom))
532 // Sys_Error ("FloorDivMod: non-integer numer or denom %f %f\n",
533 // numer, denom);
534 #endif
535
536 if (numer >= 0.0)
537 {
538
539 x = floor(numer / denom);
540 q = (int)x;
541 r = (int)floor(numer - (x * denom));
542 }
543 else
544 {
545 //
546 // perform operations with positive values, and fix mod to make floor-based
547 //
548 x = floor(-numer / denom);
549 q = -(int)x;
550 r = (int)floor(-numer - (x * denom));
551 if (r != 0)
552 {
553 q--;
554 r = (int)denom - r;
555 }
556 }
557
558 *quotient = q;
559 *rem = r;
560 }
561
562
563 /*
564 ===================
565 GreatestCommonDivisor
566 ====================
567 */
GreatestCommonDivisor(int i1,int i2)568 int GreatestCommonDivisor (int i1, int i2)
569 {
570 if (i1 > i2)
571 {
572 if (i2 == 0)
573 return (i1);
574 return GreatestCommonDivisor (i2, i1 % i2);
575 }
576 else
577 {
578 if (i1 == 0)
579 return (i2);
580 return GreatestCommonDivisor (i1, i2 % i1);
581 }
582 }
583
584
585 /*
586 ===================
587 Invert24To16
588
589 Inverts an 8.24 value to a 16.16 value
590 ====================
591 */
592
Invert24To16(fixed16_t val)593 fixed16_t Invert24To16(fixed16_t val)
594 {
595 if (val < 256)
596 return (0xFFFFFFFF);
597
598 return (fixed16_t)
599 (((double)0x10000 * (double)0x1000000 / (double)val) + 0.5);
600 }
601
602 /*
603 ===================
604 MatrixMultiply
605 ====================
606 */
MatrixMultiply(float left[16],float right[16])607 void MatrixMultiply(float left[16], float right[16])
608 {
609 float temp[16];
610 int column, row, i;
611
612 memcpy(temp, left, 16 * sizeof(float));
613 for(row = 0; row < 4; ++row)
614 {
615 for(column = 0; column < 4; ++column)
616 {
617 float value = 0.0f;
618 for (i = 0; i < 4; ++i)
619 value += temp[i*4 + row] * right[column*4 + i];
620
621 left[column * 4 + row] = value;
622 }
623 }
624 }
625
626 /*
627 =============
628 RotationMatrix
629 =============
630 */
RotationMatrix(float matrix[16],float angle,float x,float y,float z)631 void RotationMatrix(float matrix[16], float angle, float x, float y, float z)
632 {
633 const float c = cosf(angle);
634 const float s = sinf(angle);
635
636 // First column
637 matrix[0*4 + 0] = x * x * (1.0f - c) + c;
638 matrix[0*4 + 1] = y * x * (1.0f - c) + z * s;
639 matrix[0*4 + 2] = x * z * (1.0f - c) - y * s;
640 matrix[0*4 + 3] = 0.0f;
641
642 // Second column
643 matrix[1*4 + 0] = x * y * (1.0f - c) - z * s;
644 matrix[1*4 + 1] = y * y * (1.0f - c) + c;
645 matrix[1*4 + 2] = y * z * (1.0f - c) + x * s;
646 matrix[1*4 + 3] = 0.0f;
647
648 // Third column
649 matrix[2*4 + 0] = x * z * (1.0f - c) + y * s;
650 matrix[2*4 + 1] = y * z * (1.0f - c) - x * s;
651 matrix[2*4 + 2] = z * z * (1.0f - c) + c;
652 matrix[2*4 + 3] = 0.0f;
653
654 // Fourth column
655 matrix[3*4 + 0] = 0.0f;
656 matrix[3*4 + 1] = 0.0f;
657 matrix[3*4 + 2] = 0.0f;
658 matrix[3*4 + 3] = 1.0f;
659 }
660
661 /*
662 =============
663 TranslationMatrix
664 =============
665 */
TranslationMatrix(float matrix[16],float x,float y,float z)666 void TranslationMatrix(float matrix[16], float x, float y, float z)
667 {
668 memset(matrix, 0, 16 * sizeof(float));
669
670 // First column
671 matrix[0*4 + 0] = 1.0f;
672
673 // Second column
674 matrix[1*4 + 1] = 1.0f;
675
676 // Third column
677 matrix[2*4 + 2] = 1.0f;
678
679 // Fourth column
680 matrix[3*4 + 0] = x;
681 matrix[3*4 + 1] = y;
682 matrix[3*4 + 2] = z;
683 matrix[3*4 + 3] = 1.0f;
684 }
685
686 /*
687 =============
688 ScaleMatrix
689 =============
690 */
ScaleMatrix(float matrix[16],float x,float y,float z)691 void ScaleMatrix(float matrix[16], float x, float y, float z)
692 {
693 memset(matrix, 0, 16 * sizeof(float));
694
695 // First column
696 matrix[0*4 + 0] = x;
697
698 // Second column
699 matrix[1*4 + 1] = y;
700
701 // Third column
702 matrix[2*4 + 2] = z;
703
704 // Fourth column
705 matrix[3*4 + 3] = 1.0f;
706 }
707
708 /*
709 =============
710 IdentityMatrix
711 =============
712 */
IdentityMatrix(float matrix[16])713 void IdentityMatrix(float matrix[16])
714 {
715 memset(matrix, 0, 16 * sizeof(float));
716
717 // First column
718 matrix[0*4 + 0] = 1.0f;
719
720 // Second column
721 matrix[1*4 + 1] = 1.0f;
722
723 // Third column
724 matrix[2*4 + 2] = 1.0f;
725
726 // Fourth column
727 matrix[3*4 + 3] = 1.0f;
728 }
729
IsOriginWithinMinMax(vec3_t origin,vec3_t mins,vec3_t maxs)730 qboolean IsOriginWithinMinMax(vec3_t origin, vec3_t mins, vec3_t maxs){
731 return origin[0] > mins[0] && origin[1] > mins[1] && origin[2] > mins[2]
732 && origin[0] < maxs[0] && origin[1] < maxs[1] && origin[2] < maxs[2];
733 }
734
735 //is angle (in degrees) within an arcsec of a mulitple of 90 degrees (ignoring gimbal lock)
IsAxisAlignedDeg(vec3_t angle)736 qboolean IsAxisAlignedDeg(vec3_t angle){
737 int remainder[3] = {
738 ((int)(angle[0]*ARRSECS_PER_DEGREE) + 1) % ARCSECS_PER_RIGHT_ANGLE,
739 ((int)(angle[1]*ARRSECS_PER_DEGREE) + 1) % ARCSECS_PER_RIGHT_ANGLE,
740 ((int)(angle[2]*ARRSECS_PER_DEGREE) + 1) % ARCSECS_PER_RIGHT_ANGLE
741 };
742
743 return (remainder[0] <= 2) && (remainder[1] <= 2) && (remainder[2] <= 2);
744 }
745