PageRenderTime 74ms CodeModel.GetById 37ms RepoModel.GetById 0ms app.codeStats 0ms

/game/q_shared.c

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