1 // this file is not distributed under the GNU General Public License
2 // refer to id_license.txt for the id source license
3
4 #include <assert.h>
5 #include <math.h>
6 #include <stdio.h>
7 #include <stdarg.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <time.h>
11
12 #include "shared.h"
13 #include "q2utils.h"
14
15 #ifdef WIN32
16 #pragma warning(disable: 4244) // double to float conversion
17 #pragma warning(disable: 4018) // signed/unsigned mismatch
18 #endif
19
20 #define DEG2RAD( a ) ( a * M_PI ) / 180.0F
21
22 vec3_t vec3_origin = {0,0,0};
23
24 //============================================================================
25
26 #ifdef _WIN32
27 #pragma optimize( "", off )
28 #endif
29
RotatePointAroundVector(vec3_t dst,const vec3_t dir,const vec3_t point,float degrees)30 void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees )
31 {
32 float m[3][3];
33 float im[3][3];
34 float zrot[3][3];
35 float tmpmat[3][3];
36 float rot[3][3];
37 int i;
38 vec3_t vr, vup, vf;
39
40 vf[0] = dir[0];
41 vf[1] = dir[1];
42 vf[2] = dir[2];
43
44 PerpendicularVector( vr, dir );
45 CrossProduct( vr, vf, vup );
46
47 m[0][0] = vr[0];
48 m[1][0] = vr[1];
49 m[2][0] = vr[2];
50
51 m[0][1] = vup[0];
52 m[1][1] = vup[1];
53 m[2][1] = vup[2];
54
55 m[0][2] = vf[0];
56 m[1][2] = vf[1];
57 m[2][2] = vf[2];
58
59 memcpy( im, m, sizeof( im ) );
60
61 im[0][1] = m[1][0];
62 im[0][2] = m[2][0];
63 im[1][0] = m[0][1];
64 im[1][2] = m[2][1];
65 im[2][0] = m[0][2];
66 im[2][1] = m[1][2];
67
68 memset( zrot, 0, sizeof( zrot ) );
69 zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F;
70
71 zrot[0][0] = cos( DEG2RAD( degrees ) );
72 zrot[0][1] = sin( DEG2RAD( degrees ) );
73 zrot[1][0] = -sin( DEG2RAD( degrees ) );
74 zrot[1][1] = cos( DEG2RAD( degrees ) );
75
76 R_ConcatRotations( m, zrot, tmpmat );
77 R_ConcatRotations( tmpmat, im, rot );
78
79 for ( i = 0; i < 3; i++ )
80 {
81 dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2];
82 }
83 }
84
85 #ifdef _WIN32
86 #pragma optimize( "", on )
87 #endif
88
89
90
AngleVectors(vec3_t angles,vec3_t forward,vec3_t right,vec3_t up)91 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
92 {
93 float angle;
94 static float sr, sp, sy, cr, cp, cy;
95 // static to help MS compiler fp bugs
96
97 angle = angles[YAW] * (M_PI*2 / 360);
98 sy = sin(angle);
99 cy = cos(angle);
100 angle = angles[PITCH] * (M_PI*2 / 360);
101 sp = sin(angle);
102 cp = cos(angle);
103 angle = angles[ROLL] * (M_PI*2 / 360);
104 sr = sin(angle);
105 cr = cos(angle);
106
107 if (forward)
108 {
109 forward[0] = cp*cy;
110 forward[1] = cp*sy;
111 forward[2] = -sp;
112 }
113 if (right)
114 {
115 right[0] = (-1*sr*sp*cy+-1*cr*-sy);
116 right[1] = (-1*sr*sp*sy+-1*cr*cy);
117 right[2] = -1*sr*cp;
118 }
119 if (up)
120 {
121 up[0] = (cr*sp*cy+-sr*-sy);
122 up[1] = (cr*sp*sy+-sr*cy);
123 up[2] = cr*cp;
124 }
125 }
126
ProjectPointOnPlane(vec3_t dst,const vec3_t p,const vec3_t normal)127 void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal )
128 {
129 float d;
130 vec3_t n;
131 float inv_denom;
132
133 inv_denom = 1.0F / DotProduct( normal, normal );
134
135 d = DotProduct( normal, p ) * inv_denom;
136
137 n[0] = normal[0] * inv_denom;
138 n[1] = normal[1] * inv_denom;
139 n[2] = normal[2] * inv_denom;
140
141 dst[0] = p[0] - d * n[0];
142 dst[1] = p[1] - d * n[1];
143 dst[2] = p[2] - d * n[2];
144 }
145
146 /*
147 ** assumes "src" is normalized
148 */
PerpendicularVector(vec3_t dst,const vec3_t src)149 void PerpendicularVector( vec3_t dst, const vec3_t src )
150 {
151 int pos;
152 int i;
153 float minelem = 1.0F;
154 vec3_t tempvec;
155
156 /*
157 ** find the smallest magnitude axially aligned vector
158 */
159 for ( pos = 0, i = 0; i < 3; i++ )
160 {
161 if ( fabs( src[i] ) < minelem )
162 {
163 pos = i;
164 minelem = fabs( src[i] );
165 }
166 }
167 tempvec[0] = tempvec[1] = tempvec[2] = 0.0F;
168 tempvec[pos] = 1.0F;
169
170 /*
171 ** project the point onto the plane defined by src
172 */
173 ProjectPointOnPlane( dst, tempvec, src );
174
175 /*
176 ** normalize the result
177 */
178 VectorNormalize( dst );
179 }
180
181
182
183 /*
184 ================
185 R_ConcatRotations
186 ================
187 */
R_ConcatRotations(float in1[3][3],float in2[3][3],float out[3][3])188 void R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3])
189 {
190 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
191 in1[0][2] * in2[2][0];
192 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
193 in1[0][2] * in2[2][1];
194 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
195 in1[0][2] * in2[2][2];
196 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
197 in1[1][2] * in2[2][0];
198 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
199 in1[1][2] * in2[2][1];
200 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
201 in1[1][2] * in2[2][2];
202 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
203 in1[2][2] * in2[2][0];
204 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
205 in1[2][2] * in2[2][1];
206 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
207 in1[2][2] * in2[2][2];
208 }
209
210
211 /*
212 ================
213 R_ConcatTransforms
214 ================
215 */
R_ConcatTransforms(float in1[3][4],float in2[3][4],float out[3][4])216 void R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4])
217 {
218 out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] +
219 in1[0][2] * in2[2][0];
220 out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] +
221 in1[0][2] * in2[2][1];
222 out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] +
223 in1[0][2] * in2[2][2];
224 out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] +
225 in1[0][2] * in2[2][3] + in1[0][3];
226 out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] +
227 in1[1][2] * in2[2][0];
228 out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] +
229 in1[1][2] * in2[2][1];
230 out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] +
231 in1[1][2] * in2[2][2];
232 out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] +
233 in1[1][2] * in2[2][3] + in1[1][3];
234 out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] +
235 in1[2][2] * in2[2][0];
236 out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] +
237 in1[2][2] * in2[2][1];
238 out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] +
239 in1[2][2] * in2[2][2];
240 out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] +
241 in1[2][2] * in2[2][3] + in1[2][3];
242 }
243
244
245 //============================================================================
246
247
Q_fabs(float f)248 float Q_fabs (float f)
249 {
250 #if 0
251 if (f >= 0)
252 return f;
253 return -f;
254 #else
255 int tmp = * ( int * ) &f;
256 tmp &= 0x7FFFFFFF;
257 return * ( float * ) &tmp;
258 #endif
259 }
260
261 #if defined _M_IX86 && !defined C_ONLY
262 #pragma warning (disable:4035)
Q_ftol(float f)263 __declspec( naked ) long Q_ftol( float f )
264 {
265 static int tmp;
266 __asm fld dword ptr [esp+4]
267 __asm fistp tmp
268 __asm mov eax, tmp
269 __asm ret
270 }
271 #pragma warning (default:4035)
272 #endif
273
274 /*
275 ===============
276 LerpAngle
277
278 ===============
279 */
LerpAngle(float a2,float a1,float frac)280 float LerpAngle (float a2, float a1, float frac)
281 {
282 if (a1 - a2 > 180)
283 a1 -= 360;
284 if (a1 - a2 < -180)
285 a1 += 360;
286 return a2 + frac * (a1 - a2);
287 }
288
289
anglemod(float a)290 float anglemod(float a)
291 {
292 #if 0
293 if (a >= 0)
294 a -= 360*(int)(a/360);
295 else
296 a += 360*( 1 + (int)(-a/360) );
297 #endif
298 a = (360.0/65536) * ((int)(a*(65536/360.0)) & 65535);
299 return a;
300 }
301
302 int i;
303 vec3_t corners[2];
304
305
306 // this is the slow, general version
BoxOnPlaneSide2(vec3_t emins,vec3_t emaxs,struct cplane_s * p)307 int BoxOnPlaneSide2 (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
308 {
309 int i;
310 float dist1, dist2;
311 int sides;
312 vec3_t corners[2];
313
314 for (i=0 ; i<3 ; i++)
315 {
316 if (p->normal[i] < 0)
317 {
318 corners[0][i] = emins[i];
319 corners[1][i] = emaxs[i];
320 }
321 else
322 {
323 corners[1][i] = emins[i];
324 corners[0][i] = emaxs[i];
325 }
326 }
327 dist1 = DotProduct (p->normal, corners[0]) - p->dist;
328 dist2 = DotProduct (p->normal, corners[1]) - p->dist;
329 sides = 0;
330 if (dist1 >= 0)
331 sides = 1;
332 if (dist2 < 0)
333 sides |= 2;
334
335 return sides;
336 }
337
338 /*
339 ==================
340 BoxOnPlaneSide
341
342 Returns 1, 2, or 1 + 2
343 ==================
344 */
345 #if !id386 || defined __linux__
BoxOnPlaneSide(vec3_t emins,vec3_t emaxs,struct cplane_s * p)346 int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
347 {
348 float dist1, dist2;
349 int sides;
350
351 // fast axial cases
352 if (p->type < 3)
353 {
354 if (p->dist <= emins[p->type])
355 return 1;
356 if (p->dist >= emaxs[p->type])
357 return 2;
358 return 3;
359 }
360
361 // general case
362 switch (p->signbits)
363 {
364 case 0:
365 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
366 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
367 break;
368 case 1:
369 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
370 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
371 break;
372 case 2:
373 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
374 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
375 break;
376 case 3:
377 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
378 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
379 break;
380 case 4:
381 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
382 dist2 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
383 break;
384 case 5:
385 dist1 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emins[2];
386 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emaxs[2];
387 break;
388 case 6:
389 dist1 = p->normal[0]*emaxs[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
390 dist2 = p->normal[0]*emins[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
391 break;
392 case 7:
393 dist1 = p->normal[0]*emins[0] + p->normal[1]*emins[1] + p->normal[2]*emins[2];
394 dist2 = p->normal[0]*emaxs[0] + p->normal[1]*emaxs[1] + p->normal[2]*emaxs[2];
395 break;
396 default:
397 dist1 = dist2 = 0; // shut up compiler
398 assert( 0 );
399 break;
400 }
401
402 sides = 0;
403 if (dist1 >= p->dist)
404 sides = 1;
405 if (dist2 < p->dist)
406 sides |= 2;
407
408 assert( sides != 0 );
409
410 return sides;
411 }
412 #else
413 #pragma warning( disable: 4035 )
414
BoxOnPlaneSide(vec3_t emins,vec3_t emaxs,struct cplane_s * p)415 __declspec( naked ) int BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct cplane_s *p)
416 {
417 static int bops_initialized;
418 static int Ljmptab[8];
419
420 __asm {
421
422 push ebx
423
424 cmp bops_initialized, 1
425 je initialized
426 mov bops_initialized, 1
427
428 mov Ljmptab[0*4], offset Lcase0
429 mov Ljmptab[1*4], offset Lcase1
430 mov Ljmptab[2*4], offset Lcase2
431 mov Ljmptab[3*4], offset Lcase3
432 mov Ljmptab[4*4], offset Lcase4
433 mov Ljmptab[5*4], offset Lcase5
434 mov Ljmptab[6*4], offset Lcase6
435 mov Ljmptab[7*4], offset Lcase7
436
437 initialized:
438
439 mov edx,ds:dword ptr[4+12+esp]
440 mov ecx,ds:dword ptr[4+4+esp]
441 xor eax,eax
442 mov ebx,ds:dword ptr[4+8+esp]
443 mov al,ds:byte ptr[17+edx]
444 cmp al,8
445 jge Lerror
446 fld ds:dword ptr[0+edx]
447 fld st(0)
448 jmp dword ptr[Ljmptab+eax*4]
449 Lcase0:
450 fmul ds:dword ptr[ebx]
451 fld ds:dword ptr[0+4+edx]
452 fxch st(2)
453 fmul ds:dword ptr[ecx]
454 fxch st(2)
455 fld st(0)
456 fmul ds:dword ptr[4+ebx]
457 fld ds:dword ptr[0+8+edx]
458 fxch st(2)
459 fmul ds:dword ptr[4+ecx]
460 fxch st(2)
461 fld st(0)
462 fmul ds:dword ptr[8+ebx]
463 fxch st(5)
464 faddp st(3),st(0)
465 fmul ds:dword ptr[8+ecx]
466 fxch st(1)
467 faddp st(3),st(0)
468 fxch st(3)
469 faddp st(2),st(0)
470 jmp LSetSides
471 Lcase1:
472 fmul ds:dword ptr[ecx]
473 fld ds:dword ptr[0+4+edx]
474 fxch st(2)
475 fmul ds:dword ptr[ebx]
476 fxch st(2)
477 fld st(0)
478 fmul ds:dword ptr[4+ebx]
479 fld ds:dword ptr[0+8+edx]
480 fxch st(2)
481 fmul ds:dword ptr[4+ecx]
482 fxch st(2)
483 fld st(0)
484 fmul ds:dword ptr[8+ebx]
485 fxch st(5)
486 faddp st(3),st(0)
487 fmul ds:dword ptr[8+ecx]
488 fxch st(1)
489 faddp st(3),st(0)
490 fxch st(3)
491 faddp st(2),st(0)
492 jmp LSetSides
493 Lcase2:
494 fmul ds:dword ptr[ebx]
495 fld ds:dword ptr[0+4+edx]
496 fxch st(2)
497 fmul ds:dword ptr[ecx]
498 fxch st(2)
499 fld st(0)
500 fmul ds:dword ptr[4+ecx]
501 fld ds:dword ptr[0+8+edx]
502 fxch st(2)
503 fmul ds:dword ptr[4+ebx]
504 fxch st(2)
505 fld st(0)
506 fmul ds:dword ptr[8+ebx]
507 fxch st(5)
508 faddp st(3),st(0)
509 fmul ds:dword ptr[8+ecx]
510 fxch st(1)
511 faddp st(3),st(0)
512 fxch st(3)
513 faddp st(2),st(0)
514 jmp LSetSides
515 Lcase3:
516 fmul ds:dword ptr[ecx]
517 fld ds:dword ptr[0+4+edx]
518 fxch st(2)
519 fmul ds:dword ptr[ebx]
520 fxch st(2)
521 fld st(0)
522 fmul ds:dword ptr[4+ecx]
523 fld ds:dword ptr[0+8+edx]
524 fxch st(2)
525 fmul ds:dword ptr[4+ebx]
526 fxch st(2)
527 fld st(0)
528 fmul ds:dword ptr[8+ebx]
529 fxch st(5)
530 faddp st(3),st(0)
531 fmul ds:dword ptr[8+ecx]
532 fxch st(1)
533 faddp st(3),st(0)
534 fxch st(3)
535 faddp st(2),st(0)
536 jmp LSetSides
537 Lcase4:
538 fmul ds:dword ptr[ebx]
539 fld ds:dword ptr[0+4+edx]
540 fxch st(2)
541 fmul ds:dword ptr[ecx]
542 fxch st(2)
543 fld st(0)
544 fmul ds:dword ptr[4+ebx]
545 fld ds:dword ptr[0+8+edx]
546 fxch st(2)
547 fmul ds:dword ptr[4+ecx]
548 fxch st(2)
549 fld st(0)
550 fmul ds:dword ptr[8+ecx]
551 fxch st(5)
552 faddp st(3),st(0)
553 fmul ds:dword ptr[8+ebx]
554 fxch st(1)
555 faddp st(3),st(0)
556 fxch st(3)
557 faddp st(2),st(0)
558 jmp LSetSides
559 Lcase5:
560 fmul ds:dword ptr[ecx]
561 fld ds:dword ptr[0+4+edx]
562 fxch st(2)
563 fmul ds:dword ptr[ebx]
564 fxch st(2)
565 fld st(0)
566 fmul ds:dword ptr[4+ebx]
567 fld ds:dword ptr[0+8+edx]
568 fxch st(2)
569 fmul ds:dword ptr[4+ecx]
570 fxch st(2)
571 fld st(0)
572 fmul ds:dword ptr[8+ecx]
573 fxch st(5)
574 faddp st(3),st(0)
575 fmul ds:dword ptr[8+ebx]
576 fxch st(1)
577 faddp st(3),st(0)
578 fxch st(3)
579 faddp st(2),st(0)
580 jmp LSetSides
581 Lcase6:
582 fmul ds:dword ptr[ebx]
583 fld ds:dword ptr[0+4+edx]
584 fxch st(2)
585 fmul ds:dword ptr[ecx]
586 fxch st(2)
587 fld st(0)
588 fmul ds:dword ptr[4+ecx]
589 fld ds:dword ptr[0+8+edx]
590 fxch st(2)
591 fmul ds:dword ptr[4+ebx]
592 fxch st(2)
593 fld st(0)
594 fmul ds:dword ptr[8+ecx]
595 fxch st(5)
596 faddp st(3),st(0)
597 fmul ds:dword ptr[8+ebx]
598 fxch st(1)
599 faddp st(3),st(0)
600 fxch st(3)
601 faddp st(2),st(0)
602 jmp LSetSides
603 Lcase7:
604 fmul ds:dword ptr[ecx]
605 fld ds:dword ptr[0+4+edx]
606 fxch st(2)
607 fmul ds:dword ptr[ebx]
608 fxch st(2)
609 fld st(0)
610 fmul ds:dword ptr[4+ecx]
611 fld ds:dword ptr[0+8+edx]
612 fxch st(2)
613 fmul ds:dword ptr[4+ebx]
614 fxch st(2)
615 fld st(0)
616 fmul ds:dword ptr[8+ecx]
617 fxch st(5)
618 faddp st(3),st(0)
619 fmul ds:dword ptr[8+ebx]
620 fxch st(1)
621 faddp st(3),st(0)
622 fxch st(3)
623 faddp st(2),st(0)
624 LSetSides:
625 faddp st(2),st(0)
626 fcomp ds:dword ptr[12+edx]
627 xor ecx,ecx
628 fnstsw ax
629 fcomp ds:dword ptr[12+edx]
630 and ah,1
631 xor ah,1
632 add cl,ah
633 fnstsw ax
634 and ah,1
635 add ah,ah
636 add cl,ah
637 pop ebx
638 mov eax,ecx
639 ret
640 Lerror:
641 int 3
642 }
643 }
644 #pragma warning( default: 4035 )
645 #endif
646
ClearBounds(vec3_t mins,vec3_t maxs)647 void ClearBounds (vec3_t mins, vec3_t maxs)
648 {
649 mins[0] = mins[1] = mins[2] = 99999;
650 maxs[0] = maxs[1] = maxs[2] = -99999;
651 }
652
AddPointToBounds(vec3_t v,vec3_t mins,vec3_t maxs)653 void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs)
654 {
655 int i;
656 vec_t val;
657
658 for (i=0 ; i<3 ; i++)
659 {
660 val = v[i];
661 if (val < mins[i])
662 mins[i] = val;
663 if (val > maxs[i])
664 maxs[i] = val;
665 }
666 }
667
668 /*
669 int VectorCompare (vec3_t v1, vec3_t v2)
670 {
671 if (v1[0] != v2[0] || v1[1] != v2[1] || v1[2] != v2[2])
672 return 0;
673
674 return 1;
675 }
676 */
677
VectorNormalize(vec3_t v)678 vec_t VectorNormalize (vec3_t v)
679 {
680 float length, ilength;
681
682 length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
683 length = sqrt (length); // FIXME
684
685 if (length)
686 {
687 ilength = 1/length;
688 v[0] *= ilength;
689 v[1] *= ilength;
690 v[2] *= ilength;
691 }
692
693 return length;
694
695 }
696
VectorNormalize2(vec3_t v,vec3_t out)697 vec_t VectorNormalize2 (vec3_t v, vec3_t out)
698 {
699 float length, ilength;
700
701 length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
702 length = sqrt (length); // FIXME
703
704 if (length)
705 {
706 ilength = 1/length;
707 out[0] = v[0]*ilength;
708 out[1] = v[1]*ilength;
709 out[2] = v[2]*ilength;
710 }
711
712 return length;
713
714 }
715
VectorMA(vec3_t veca,float scale,vec3_t vecb,vec3_t vecc)716 void VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)
717 {
718 vecc[0] = veca[0] + scale*vecb[0];
719 vecc[1] = veca[1] + scale*vecb[1];
720 vecc[2] = veca[2] + scale*vecb[2];
721 }
722
723
_DotProduct(vec3_t v1,vec3_t v2)724 vec_t _DotProduct (vec3_t v1, vec3_t v2)
725 {
726 return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
727 }
728
_VectorSubtract(vec3_t veca,vec3_t vecb,vec3_t out)729 void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out)
730 {
731 out[0] = veca[0]-vecb[0];
732 out[1] = veca[1]-vecb[1];
733 out[2] = veca[2]-vecb[2];
734 }
735
_VectorAdd(vec3_t veca,vec3_t vecb,vec3_t out)736 void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out)
737 {
738 out[0] = veca[0]+vecb[0];
739 out[1] = veca[1]+vecb[1];
740 out[2] = veca[2]+vecb[2];
741 }
742
_VectorCopy(vec3_t in,vec3_t out)743 void _VectorCopy (vec3_t in, vec3_t out)
744 {
745 out[0] = in[0];
746 out[1] = in[1];
747 out[2] = in[2];
748 }
749
CrossProduct(vec3_t v1,vec3_t v2,vec3_t cross)750 void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross)
751 {
752 cross[0] = v1[1]*v2[2] - v1[2]*v2[1];
753 cross[1] = v1[2]*v2[0] - v1[0]*v2[2];
754 cross[2] = v1[0]*v2[1] - v1[1]*v2[0];
755 }
756
757 double sqrt(double x);
758
VectorLength(vec3_t v)759 vec_t VectorLength(vec3_t v)
760 {
761 int i;
762 float length;
763
764 length = 0;
765 for (i=0 ; i< 3 ; i++)
766 length += v[i]*v[i];
767 length = sqrt (length); // FIXME
768
769 return length;
770 }
771
VectorInverse(vec3_t v)772 void VectorInverse (vec3_t v)
773 {
774 v[0] = -v[0];
775 v[1] = -v[1];
776 v[2] = -v[2];
777 }
778
VectorScale(vec3_t in,vec_t scale,vec3_t out)779 void VectorScale (vec3_t in, vec_t scale, vec3_t out)
780 {
781 out[0] = in[0]*scale;
782 out[1] = in[1]*scale;
783 out[2] = in[2]*scale;
784 }
785
786
Q_log2(int val)787 int Q_log2(int val)
788 {
789 int answer=0;
790 while (val>>=1)
791 answer++;
792 return answer;
793 }
794
795
796
797 //====================================================================================
798
799 /*
800 ============
801 COM_SkipPath
802 ============
803 */
COM_SkipPath(char * pathname)804 char *COM_SkipPath (char *pathname)
805 {
806 char *last;
807
808 last = pathname;
809 while (*pathname)
810 {
811 if (*pathname=='/')
812 last = pathname+1;
813 pathname++;
814 }
815 return last;
816 }
817
818 /*
819 ============
820 COM_StripExtension
821 ============
822 */
COM_StripExtension(const char * in,char * out)823 void COM_StripExtension (const char *in, char *out)
824 {
825 while (*in && *in != '.')
826 *out++ = *in++;
827 *out = 0;
828 }
829
830 /*
831 ============
832 COM_FileExtension
833 ============
834 */
COM_FileExtension(const char * in)835 char *COM_FileExtension (const char *in)
836 {
837 static char exten[8];
838 int i;
839
840 while (*in && *in != '.')
841 in++;
842 if (!*in)
843 return "";
844 in++;
845 for (i=0 ; i<7 && *in ; i++,in++)
846 exten[i] = *in;
847 exten[i] = 0;
848 return exten;
849 }
850
851 /*
852 ============
853 COM_FileBase
854 ============
855 */
COM_FileBase(const char * in,char * out)856 void COM_FileBase (const char *in, char *out)
857 {
858 const char *s, *s2;
859
860 s = in + strlen(in) - 1;
861
862 while (s != in && *s != '.')
863 s--;
864
865 for (s2 = s ; s2 != in && *s2 != '/' ; s2--)
866 ;
867
868 if (s-s2 < 2)
869 out[0] = 0;
870 else
871 {
872 s--;
873 strncpy (out,s2+1, s-s2);
874 out[s-s2] = 0;
875 }
876 }
877
878 /*
879 ============
880 COM_FilePath
881
882 Returns the path up to, but not including the last /
883 ============
884 */
COM_FilePath(const char * in,char * out)885 void COM_FilePath (const char *in, char *out)
886 {
887 const char *s;
888
889 s = in + strlen(in) - 1;
890
891 while (s != in && *s != '/')
892 s--;
893
894 strncpy (out,in, s-in);
895 out[s-in] = 0;
896 }
897
898
899 /*
900 ==================
901 COM_DefaultExtension
902 ==================
903 */
COM_DefaultExtension(char * path,const char * extension)904 void COM_DefaultExtension (char *path, const char *extension)
905 {
906 char *src;
907 //
908 // if path doesn't have a .EXT, append extension
909 // (extension should include the .)
910 //
911 src = path + strlen(path) - 1;
912
913 while (*src != '/' && src != path)
914 {
915 if (*src == '.')
916 return; // it has an extension
917 src--;
918 }
919
920 strcat(path, extension);
921 }
922
923 /*
924 ============
925 va
926
927 does a varargs printf into a temp buffer, so I don't need to have
928 varargs versions of all text functions.
929 FIXME: make this buffer size safe someday
930 ============
931 */
va(const char * format,...)932 char *va(const char *format, ...)
933 {
934 va_list argptr;
935 static char string[1024];
936
937 va_start(argptr, format);
938 vsprintf(string, format, argptr);
939 va_end(argptr);
940
941 return string;
942 }
943
944
945 char com_token[MAX_TOKEN_CHARS];
946
947 /*
948 ==============
949 COM_Parse
950
951 Parse a token out of a string
952 ==============
953 */
COM_Parse(char ** data_p)954 char *COM_Parse (char **data_p)
955 {
956 int c;
957 int len;
958 char *data;
959
960 data = *data_p;
961 len = 0;
962 com_token[0] = 0;
963
964 if (!data)
965 {
966 *data_p = NULL;
967 return "";
968 }
969
970 // skip whitespace
971 skipwhite:
972 while ( (c = *data) <= ' ')
973 {
974 if (c == 0)
975 {
976 *data_p = NULL;
977 return "";
978 }
979 data++;
980 }
981
982 // skip // comments
983 if (c=='/' && data[1] == '/')
984 {
985 while (*data && *data != '\n')
986 data++;
987 goto skipwhite;
988 }
989
990 // handle quoted strings specially
991 if (c == '\"')
992 {
993 data++;
994 while (1)
995 {
996 c = *data++;
997 if (c=='\"' || !c)
998 {
999 com_token[len] = 0;
1000 *data_p = data;
1001 return com_token;
1002 }
1003 if (len < MAX_TOKEN_CHARS)
1004 {
1005 com_token[len] = c;
1006 len++;
1007 }
1008 }
1009 }
1010
1011 // parse a regular word
1012 do
1013 {
1014 if (len < MAX_TOKEN_CHARS)
1015 {
1016 com_token[len] = c;
1017 len++;
1018 }
1019 data++;
1020 c = *data;
1021 } while (c>32);
1022
1023 if (len == MAX_TOKEN_CHARS)
1024 {
1025 Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
1026 len = 0;
1027 }
1028 com_token[len] = 0;
1029
1030 *data_p = data;
1031 return com_token;
1032 }
1033
1034
1035 /*
1036 ===============
1037 Com_PageInMemory
1038
1039 ===============
1040 */
1041 int paged_total;
1042
Com_PageInMemory(byte * buffer,int size)1043 void Com_PageInMemory (byte *buffer, int size)
1044 {
1045 int i;
1046
1047 for (i=size-1 ; i>0 ; i-=4096)
1048 paged_total += buffer[i];
1049 }
1050
1051
1052
1053 /*
1054 ============================================================================
1055
1056 LIBRARY REPLACEMENT FUNCTIONS
1057
1058 ============================================================================
1059 */
1060
1061 // FIXME: replace all Q_stricmp with Q_strcasecmp
Q_stricmp(const char * s1,const char * s2)1062 int Q_stricmp (const char *s1, const char *s2)
1063 {
1064 #if defined(WIN32)
1065 return _stricmp (s1, s2);
1066 #else
1067 return strcasecmp (s1, s2);
1068 #endif
1069 }
1070
1071
Q_strncasecmp(const char * s1,const char * s2,int n)1072 int Q_strncasecmp (const char *s1, const char *s2, int n)
1073 {
1074 int c1, c2;
1075
1076 do
1077 {
1078 c1 = *s1++;
1079 c2 = *s2++;
1080
1081 if (!n--)
1082 return 0; // strings are equal until end point
1083
1084 if (c1 != c2)
1085 {
1086 if (c1 >= 'a' && c1 <= 'z')
1087 c1 -= ('a' - 'A');
1088 if (c2 >= 'a' && c2 <= 'z')
1089 c2 -= ('a' - 'A');
1090 if (c1 != c2)
1091 return -1; // strings not equal
1092 }
1093 } while (c1);
1094
1095 return 0; // strings are equal
1096 }
1097
Q_strcasecmp(const char * s1,const char * s2)1098 int Q_strcasecmp (const char *s1, const char *s2)
1099 {
1100 return Q_strncasecmp (s1, s2, 99999);
1101 }
1102
1103
1104
Com_sprintf(char * dest,int size,const char * fmt,...)1105 void Com_sprintf (char *dest, int size, const char *fmt, ...)
1106 {
1107 int len;
1108 va_list argptr;
1109 char bigbuffer[0x10000];
1110
1111 va_start (argptr,fmt);
1112 len = vsprintf (bigbuffer,fmt,argptr);
1113 va_end (argptr);
1114 if (len >= size)
1115 Com_Printf("Com_sprintf: overflow of %i in %i\n", len, size);
1116 strncpy (dest, bigbuffer, size-1);
1117 }
1118
1119 /*
1120 =====================================================================
1121
1122 INFO STRINGS
1123
1124 =====================================================================
1125 */
1126
1127 /*
1128 ===============
1129 Info_ValueForKey
1130
1131 Searches the string for the given
1132 key and returns the associated value, or an empty string.
1133 ===============
1134 */
Info_ValueForKey(const char * s,const char * key)1135 char *Info_ValueForKey (const char *s, const char *key)
1136 {
1137 char pkey[512];
1138 static char value[2][512]; // use two buffers so compares
1139 // work without stomping on each other
1140 static int valueindex;
1141 char *o;
1142
1143 valueindex ^= 1;
1144 if (*s == '\\')
1145 s++;
1146 while (1)
1147 {
1148 o = pkey;
1149 while (*s != '\\')
1150 {
1151 if (!*s)
1152 return "";
1153 *o++ = *s++;
1154 }
1155 *o = 0;
1156 s++;
1157
1158 o = value[valueindex];
1159
1160 while (*s != '\\' && *s)
1161 {
1162 if (!*s)
1163 return "";
1164 *o++ = *s++;
1165 }
1166 *o = 0;
1167
1168 if (!strcmp (key, pkey) )
1169 return value[valueindex];
1170
1171 if (!*s)
1172 return "";
1173 s++;
1174 }
1175 }
1176
Info_RemoveKey(char * s,const char * key)1177 void Info_RemoveKey (char *s, const char *key)
1178 {
1179 char *start;
1180 char pkey[512];
1181 char value[512];
1182 char *o;
1183
1184 if (strstr (key, "\\"))
1185 {
1186 Com_Printf ("Can't use a key with a \\\n");
1187 return;
1188 }
1189
1190 while (1)
1191 {
1192 start = s;
1193 if (*s == '\\')
1194 s++;
1195 o = pkey;
1196 while (*s != '\\')
1197 {
1198 if (!*s)
1199 return;
1200 *o++ = *s++;
1201 }
1202 *o = 0;
1203 s++;
1204
1205 o = value;
1206 while (*s != '\\' && *s)
1207 {
1208 if (!*s)
1209 return;
1210 *o++ = *s++;
1211 }
1212 *o = 0;
1213
1214 if (!strcmp (key, pkey) )
1215 {
1216 strcpy (start, s); // remove this part
1217 return;
1218 }
1219
1220 if (!*s)
1221 return;
1222 }
1223
1224 }
1225
1226
1227 /*
1228 ==================
1229 Info_Validate
1230
1231 Some characters are illegal in info strings because they
1232 can mess up the server's parsing
1233 ==================
1234 */
Info_Validate(const char * s)1235 qboolean Info_Validate (const char *s)
1236 {
1237 if (strstr (s, "\""))
1238 return false;
1239 if (strstr (s, ";"))
1240 return false;
1241 return true;
1242 }
1243
Info_SetValueForKey(char * s,const char * key,const char * value)1244 void Info_SetValueForKey (char *s, const char *key, const char *value)
1245 {
1246 char newi[MAX_INFO_STRING], *v;
1247 int c;
1248 int maxsize = MAX_INFO_STRING;
1249
1250 if (strstr (key, "\\") || strstr (value, "\\") )
1251 {
1252 Com_Printf ("Can't use keys or values with a \\\n");
1253 return;
1254 }
1255
1256 if (strstr (key, ";") )
1257 {
1258 Com_Printf ("Can't use keys or values with a semicolon\n");
1259 return;
1260 }
1261
1262 if (strstr (key, "\"") || strstr (value, "\"") )
1263 {
1264 Com_Printf ("Can't use keys or values with a \"\n");
1265 return;
1266 }
1267
1268 if (strlen(key) > MAX_INFO_KEY-1 || strlen(value) > MAX_INFO_KEY-1)
1269 {
1270 Com_Printf ("Keys and values must be < 64 characters.\n");
1271 return;
1272 }
1273 Info_RemoveKey (s, key);
1274 if (!value || !strlen(value))
1275 return;
1276
1277 Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
1278
1279 if (strlen(newi) + strlen(s) > maxsize)
1280 {
1281 Com_Printf ("Info string length exceeded\n");
1282 return;
1283 }
1284
1285 // only copy ascii values
1286 s += strlen(s);
1287 v = newi;
1288 while (*v)
1289 {
1290 c = *v++;
1291 c &= 127; // strip high bits
1292 if (c >= 32 && c < 127)
1293 *s++ = c;
1294 }
1295 *s = 0;
1296 }
1297
1298 //====================================================================
1299
1300 // from g_utils.c
G_ProjectSource(vec3_t point,vec3_t distance,vec3_t forward,vec3_t right,vec3_t result)1301 void G_ProjectSource (vec3_t point, vec3_t distance, vec3_t forward, vec3_t right, vec3_t result)
1302 {
1303 result[0] = point[0] + forward[0] * distance[0] + right[0] * distance[1];
1304 result[1] = point[1] + forward[1] * distance[0] + right[1] * distance[1];
1305 result[2] = point[2] + forward[2] * distance[0] + right[2] * distance[1] + distance[2];
1306 }
1307
1308 /*
1309 =============
1310 TempVector
1311
1312 This is just a convenience function
1313 for making temporary vectors for function calls
1314 =============
1315 */
tv(float x,float y,float z)1316 float *tv (float x, float y, float z)
1317 {
1318 static int index;
1319 static vec3_t vecs[8];
1320 float *v;
1321
1322 // use an array so that multiple tempvectors won't collide
1323 // for a while
1324 v = vecs[index];
1325 index = (index + 1)&7;
1326
1327 v[0] = x;
1328 v[1] = y;
1329 v[2] = z;
1330
1331 return v;
1332 }
1333
1334 /*
1335 =============
1336 VectorToString
1337
1338 This is just a convenience function
1339 for printing vectors
1340 =============
1341 */
vtos(vec3_t v)1342 char *vtos (vec3_t v)
1343 {
1344 static int index;
1345 static char str[8][32];
1346 char *s;
1347
1348 // use an array so that multiple vtos won't collide
1349 s = str[index];
1350 index = (index + 1)&7;
1351
1352 Com_sprintf (s, 32, "(%i %i %i)", (int)v[0], (int)v[1], (int)v[2]);
1353
1354 return s;
1355 }
1356
vectoyaw(vec3_t vec)1357 float vectoyaw (vec3_t vec)
1358 {
1359 float yaw;
1360
1361 if (/*vec[YAW] == 0 &&*/ vec[PITCH] == 0)
1362 {
1363 yaw = 0;
1364 if (vec[YAW] > 0)
1365 yaw = 90;
1366 else if (vec[YAW] < 0)
1367 yaw = -90;
1368 }
1369 else
1370 {
1371 yaw = (int) (atan2(vec[YAW], vec[PITCH]) * 180 / M_PI);
1372 if (yaw < 0)
1373 yaw += 360;
1374 }
1375
1376 return yaw;
1377 }
1378
vectoangles(vec3_t value1,vec3_t angles)1379 void vectoangles (vec3_t value1, vec3_t angles)
1380 {
1381 float forward;
1382 float yaw, pitch;
1383
1384 if (value1[1] == 0 && value1[0] == 0)
1385 {
1386 yaw = 0;
1387 if (value1[2] > 0)
1388 pitch = 90;
1389 else
1390 pitch = 270;
1391 }
1392 else
1393 {
1394 if (value1[0])
1395 yaw = (int) (atan2(value1[1], value1[0]) * 180 / M_PI);
1396 else if (value1[1] > 0)
1397 yaw = 90;
1398 else
1399 yaw = -90;
1400 if (yaw < 0)
1401 yaw += 360;
1402
1403 forward = sqrt (value1[0]*value1[0] + value1[1]*value1[1]);
1404 pitch = (int) (atan2(value1[2], forward) * 180 / M_PI);
1405 if (pitch < 0)
1406 pitch += 360;
1407 }
1408
1409 angles[PITCH] = -pitch;
1410 angles[YAW] = yaw;
1411 angles[ROLL] = 0;
1412 }
1413