File: game\q_shared.c
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
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
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
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 */
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 */
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 */
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
251 float Q_fabs (float f)
252 {
253 #if 0
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)
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 */
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
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
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 __linux__
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
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
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
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
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
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
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
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
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
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
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
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
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
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
775 void VectorInverse (vec3_t v)
776 {
777 v[0] = -v[0];
778 v[1] = -v[1];
779 v[2] = -v[2];
780 }
781
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
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 */
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 */
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 */
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 */
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 */
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 */
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
945 short BigShort(short l){return _BigShort(l);}
946 short LittleShort(short l) {return _LittleShort(l);}
947 int BigLong (int l) {return _BigLong(l);}
948 int LittleLong (int l) {return _LittleLong(l);}
949 float BigFloat (float l) {return _BigFloat(l);}
950 float LittleFloat (float l) {return _LittleFloat(l);}
951
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
962 short ShortNoSwap (short l)
963 {
964 return l;
965 }
966
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
979 int LongNoSwap (int l)
980 {
981 return l;
982 }
983
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
1001 float FloatNoSwap (float f)
1002 {
1003 return f;
1004 }
1005
1006 /*
1007 ================
1008 Swap_Init
1009 ================
1010 */
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 */
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 */
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 // handle quoted strings specially
1109 if (c == '\"')
1110 {
1111 data++;
1112 while (1)
1113 {
1114 c = *data++;
1115 if (c=='\"' || !c)
1116 {
1117 com_token[len] = 0;
1118 *data_p = data;
1119 return com_token;
1120 }
1121 if (len < MAX_TOKEN_CHARS)
1122 {
1123 com_token[len] = c;
1124 len++;
1125 }
1126 }
1127 }
1128
1129 // parse a regular word
1130 do
1131 {
1132 if (len < MAX_TOKEN_CHARS)
1133 {
1134 com_token[len] = c;
1135 len++;
1136 }
1137 data++;
1138 c = *data;
1139 } while (c>32);
1140
1141 if (len == MAX_TOKEN_CHARS)
1142 {
1143 // Com_Printf ("Token exceeded %i chars, discarded.\n", MAX_TOKEN_CHARS);
1144 len = 0;
1145 }
1146 com_token[len] = 0;
1147
1148 *data_p = data;
1149 return com_token;
1150 }
1151
1152
1153 /*
1154 ===============
1155 Com_PageInMemory
1156
1157 ===============
1158 */
1159 int paged_total;
1160
1161 void Com_PageInMemory (byte *buffer, int size)
1162 {
1163 int i;
1164
1165 for (i=size-1 ; i>0 ; i-=4096)
1166 paged_total += buffer[i];
1167 }
1168
1169
1170
1171 /*
1172 ============================================================================
1173
1174 LIBRARY REPLACEMENT FUNCTIONS
1175
1176 ============================================================================
1177 */
1178
1179 // FIXME: replace all Q_stricmp with Q_strcasecmp
1180 int Q_stricmp (char *s1, char *s2)
1181 {
1182 #if defined(WIN32)
1183 return _stricmp (s1, s2);
1186 #endif
1187 }
1188
1189
1190 int Q_strncasecmp (char *s1, char *s2, int n)
1191 {
1192 int c1, c2;
1193
1194 do
1195 {
1196 c1 = *s1++;
1197 c2 = *s2++;
1198
1199 if (!n--)
1200 return 0; // strings are equal until end point
1201
1202 if (c1 != c2)
1203 {
1204 if (c1 >= 'a' && c1 <= 'z')
1205 c1 -= ('a' - 'A');
1206 if (c2 >= 'a' && c2 <= 'z')
1207 c2 -= ('a' - 'A');
1208 if (c1 != c2)
1209 return -1; // strings not equal
1210 }
1211 } while (c1);
1212
1213 return 0; // strings are equal
1214 }
1215
1216 int Q_strcasecmp (char *s1, char *s2)
1217 {
1218 return Q_strncasecmp (s1, s2, 99999);
1219 }
1220
1221
1222
1223 void Com_sprintf (char *dest, int size, char *fmt, ...)
1224 {
1225 int len;
1226 va_list argptr;
1227 char bigbuffer[0x10000];
1228
1229 va_start (argptr,fmt);
1230 len = vsprintf (bigbuffer,fmt,argptr);
1231 va_end (argptr);
1232 if (len >= size)
1233 Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
1234 strncpy (dest, bigbuffer, size-1);
1235 }
1236
1237 /*
1238 =====================================================================
1239
1240 INFO STRINGS
1241
1242 =====================================================================
1243 */
1244
1245 /*
1246 ===============
1247 Info_ValueForKey
1248
1249 Searches the string for the given
1250 key and returns the associated value, or an empty string.
1251 ===============
1252 */
1253 char *Info_ValueForKey (char *s, char *key)
1254 {
1255 char pkey[512];
1256 static char value[2][512]; // use two buffers so compares
1257 // work without stomping on each other
1258 static int valueindex;
1259 char *o;
1260
1261 valueindex ^= 1;
1262 if (*s == '\\')
1263 s++;
1264 while (1)
1265 {
1266 o = pkey;
1267 while (*s != '\\')
1268 {
1269 if (!*s)
1270 return "";
1271 *o++ = *s++;
1272 }
1273 *o = 0;
1274 s++;
1275
1276 o = value[valueindex];
1277
1278 while (*s != '\\' && *s)
1279 {
1280 if (!*s)
1281 return "";
1282 *o++ = *s++;
1283 }
1284 *o = 0;
1285
1286 if (!strcmp (key, pkey) )
1287 return value[valueindex];
1288
1289 if (!*s)
1290 return "";
1291 s++;
1292 }
1293 }
1294
1295 void Info_RemoveKey (char *s, char *key)
1296 {
1297 char *start;
1298 char pkey[512];
1299 char value[512];
1300 char *o;
1301
1302 if (strstr (key, "\\"))
1303 {
1304 // Com_Printf ("Can't use a key with a \\\n");
1305 return;
1306 }
1307
1308 while (1)
1309 {
1310 start = s;
1311 if (*s == '\\')
1312 s++;
1313 o = pkey;
1314 while (*s != '\\')
1315 {
1316 if (!*s)
1317 return;
1318 *o++ = *s++;
1319 }
1320 *o = 0;
1321 s++;
1322
1323 o = value;
1324 while (*s != '\\' && *s)
1325 {
1326 if (!*s)
1327 return;
1328 *o++ = *s++;
1329 }
1330 *o = 0;
1331
1332 if (!strcmp (key, pkey) )
1333 {
1334 strcpy (start, s); // remove this part
1335 return;
1336 }
1337
1338 if (!*s)
1339 return;
1340 }
1341
1342 }
1343
1344
1345 /*
1346 ==================
1347 Info_Validate
1348
1349 Some characters are illegal in info strings because they
1350 can mess up the server's parsing
1351 ==================
1352 */
1353 qboolean Info_Validate (char *s)
1354 {
1355 if (strstr (s, "\""))
1356 return false;
1357 if (strstr (s, ";"))
1358 return false;
1359 return true;
1360 }
1361
1362 void Info_SetValueForKey (char *s, char *key, char *value)
1363 {
1364 char newi[MAX_INFO_STRING], *v;
1365 int c;
1366 int maxsize = MAX_INFO_STRING;
1367
1368 if (strstr (key, "\\") || strstr (value, "\\") )
1369 {
1370 Com_Printf ("Can't use keys or values with a \\\n");
1371 return;
1372 }
1373
1374 if (strstr (key, ";") )
1375 {
1376 Com_Printf ("Can't use keys or values with a semicolon\n");
1377 return;
1378 }
1379
1380 if (strstr (key, "\"") || strstr (value, "\"") )
1381 {
1382 Com_Printf ("Can't use keys or values with a \"\n");
1383 return;
1384 }
1385
1386 if (strlen(key) > MAX_INFO_KEY-1 || strlen(value) > MAX_INFO_KEY-1)
1387 {
1388 Com_Printf ("Keys and values must be < 64 characters.\n");
1389 return;
1390 }
1391 Info_RemoveKey (s, key);
1392 if (!value || !strlen(value))
1393 return;
1394
1395 Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
1396
1397 if (strlen(newi) + strlen(s) > maxsize)
1398 {
1399 Com_Printf ("Info string length exceeded\n");
1400 return;
1401 }
1402
1403 // only copy ascii values
1404 s += strlen(s);
1405 v = newi;
1406 while (*v)
1407 {
1408 c = *v++;
1409 c &= 127; // strip high bits
1410 if (c >= 32 && c < 127)
1411 *s++ = c;
1412 }
1413 *s = 0;
1414 }
1415
1416 //====================================================================
1417
1418
1419