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