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