map.c 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1999-2005 Id Software, Inc.
  4. This file is part of Quake III Arena source code.
  5. Quake III Arena source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake III Arena source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Foobar; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "qbsp.h"
  19. #include "l_bsp_hl.h"
  20. #include "l_bsp_q1.h"
  21. #include "l_bsp_q2.h"
  22. #include "l_bsp_q3.h"
  23. #include "l_bsp_sin.h"
  24. #include "l_mem.h"
  25. #include "../botlib/aasfile.h" //aas_bbox_t
  26. #include "aas_store.h" //AAS_MAX_BBOXES
  27. #include "aas_cfg.h"
  28. #define Sign(x) (x < 0 ? 1 : 0)
  29. int nummapbrushes;
  30. mapbrush_t mapbrushes[MAX_MAPFILE_BRUSHES];
  31. int nummapbrushsides;
  32. side_t brushsides[MAX_MAPFILE_BRUSHSIDES];
  33. brush_texture_t side_brushtextures[MAX_MAPFILE_BRUSHSIDES];
  34. int nummapplanes;
  35. plane_t mapplanes[MAX_MAPFILE_PLANES];
  36. int mapplaneusers[MAX_MAPFILE_PLANES];
  37. #define PLANE_HASHES 1024
  38. plane_t *planehash[PLANE_HASHES];
  39. vec3_t map_mins, map_maxs;
  40. #ifdef SIN
  41. textureref_t side_newrefs[MAX_MAPFILE_BRUSHSIDES];
  42. #endif
  43. map_texinfo_t map_texinfo[MAX_MAPFILE_TEXINFO];
  44. int map_numtexinfo;
  45. int loadedmaptype; //loaded map type
  46. // undefine to make plane finding use linear sort
  47. #define USE_HASHING
  48. int c_boxbevels;
  49. int c_edgebevels;
  50. int c_areaportals;
  51. int c_clipbrushes;
  52. int c_squattbrushes;
  53. int c_writtenbrushes;
  54. /*
  55. =============================================================================
  56. PLANE FINDING
  57. =============================================================================
  58. */
  59. //===========================================================================
  60. //
  61. // Parameter: -
  62. // Returns: -
  63. // Changes Globals: -
  64. //===========================================================================
  65. int PlaneSignBits(vec3_t normal)
  66. {
  67. int i, signbits;
  68. signbits = 0;
  69. for (i = 2; i >= 0; i--)
  70. {
  71. signbits = (signbits << 1) + Sign(normal[i]);
  72. } //end for
  73. return signbits;
  74. } //end of the function PlaneSignBits
  75. //===========================================================================
  76. //
  77. // Parameter: -
  78. // Returns: -
  79. // Changes Globals: -
  80. //===========================================================================
  81. int PlaneTypeForNormal(vec3_t normal)
  82. {
  83. vec_t ax, ay, az;
  84. // NOTE: should these have an epsilon around 1.0?
  85. if (normal[0] == 1.0 || normal[0] == -1.0)
  86. return PLANE_X;
  87. if (normal[1] == 1.0 || normal[1] == -1.0)
  88. return PLANE_Y;
  89. if (normal[2] == 1.0 || normal[2] == -1.0)
  90. return PLANE_Z;
  91. ax = fabs(normal[0]);
  92. ay = fabs(normal[1]);
  93. az = fabs(normal[2]);
  94. if (ax >= ay && ax >= az)
  95. return PLANE_ANYX;
  96. if (ay >= ax && ay >= az)
  97. return PLANE_ANYY;
  98. return PLANE_ANYZ;
  99. } //end of the function PlaneTypeForNormal
  100. //===========================================================================
  101. //
  102. // Parameter: -
  103. // Returns: -
  104. // Changes Globals: -
  105. //===========================================================================
  106. //ME NOTE: changed from 0.00001
  107. #define NORMAL_EPSILON 0.0001
  108. //ME NOTE: changed from 0.01
  109. #define DIST_EPSILON 0.02
  110. qboolean PlaneEqual(plane_t *p, vec3_t normal, vec_t dist)
  111. {
  112. #if 1
  113. if (
  114. fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON
  115. && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON
  116. && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON
  117. && fabs(p->dist - dist) < DIST_EPSILON )
  118. return true;
  119. #else
  120. if (p->normal[0] == normal[0]
  121. && p->normal[1] == normal[1]
  122. && p->normal[2] == normal[2]
  123. && p->dist == dist)
  124. return true;
  125. #endif
  126. return false;
  127. } //end of the function PlaneEqual
  128. //===========================================================================
  129. //
  130. // Parameter: -
  131. // Returns: -
  132. // Changes Globals: -
  133. //===========================================================================
  134. void AddPlaneToHash(plane_t *p)
  135. {
  136. int hash;
  137. hash = (int)fabs(p->dist) / 8;
  138. hash &= (PLANE_HASHES-1);
  139. p->hash_chain = planehash[hash];
  140. planehash[hash] = p;
  141. } //end of the function AddPlaneToHash
  142. //===========================================================================
  143. //
  144. // Parameter: -
  145. // Returns: -
  146. // Changes Globals: -
  147. //===========================================================================
  148. int CreateNewFloatPlane (vec3_t normal, vec_t dist)
  149. {
  150. plane_t *p, temp;
  151. if (VectorLength(normal) < 0.5)
  152. Error ("FloatPlane: bad normal");
  153. // create a new plane
  154. if (nummapplanes+2 > MAX_MAPFILE_PLANES)
  155. Error ("MAX_MAPFILE_PLANES");
  156. p = &mapplanes[nummapplanes];
  157. VectorCopy (normal, p->normal);
  158. p->dist = dist;
  159. p->type = (p+1)->type = PlaneTypeForNormal (p->normal);
  160. p->signbits = PlaneSignBits(p->normal);
  161. VectorSubtract (vec3_origin, normal, (p+1)->normal);
  162. (p+1)->dist = -dist;
  163. (p+1)->signbits = PlaneSignBits((p+1)->normal);
  164. nummapplanes += 2;
  165. // allways put axial planes facing positive first
  166. if (p->type < 3)
  167. {
  168. if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0)
  169. {
  170. // flip order
  171. temp = *p;
  172. *p = *(p+1);
  173. *(p+1) = temp;
  174. AddPlaneToHash (p);
  175. AddPlaneToHash (p+1);
  176. return nummapplanes - 1;
  177. }
  178. }
  179. AddPlaneToHash (p);
  180. AddPlaneToHash (p+1);
  181. return nummapplanes - 2;
  182. } //end of the function CreateNewFloatPlane
  183. //===========================================================================
  184. //
  185. // Parameter: -
  186. // Returns: -
  187. // Changes Globals: -
  188. //===========================================================================
  189. void SnapVector(vec3_t normal)
  190. {
  191. int i;
  192. for (i=0 ; i<3 ; i++)
  193. {
  194. if ( fabs(normal[i] - 1) < NORMAL_EPSILON )
  195. {
  196. VectorClear (normal);
  197. normal[i] = 1;
  198. break;
  199. }
  200. if ( fabs(normal[i] - -1) < NORMAL_EPSILON )
  201. {
  202. VectorClear (normal);
  203. normal[i] = -1;
  204. break;
  205. }
  206. }
  207. } //end of the function SnapVector
  208. //===========================================================================
  209. //
  210. // Parameter: -
  211. // Returns: -
  212. // Changes Globals: -
  213. //===========================================================================
  214. void SnapPlane(vec3_t normal, vec_t *dist)
  215. {
  216. SnapVector(normal);
  217. if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON)
  218. *dist = Q_rint(*dist);
  219. } //end of the function SnapPlane
  220. //===========================================================================
  221. //
  222. // Parameter: -
  223. // Returns: -
  224. // Changes Globals: -
  225. //===========================================================================
  226. #ifndef USE_HASHING
  227. int FindFloatPlane(vec3_t normal, vec_t dist)
  228. {
  229. int i;
  230. plane_t *p;
  231. SnapPlane(normal, &dist);
  232. for (i = 0, p = mapplanes; i < nummapplanes; i++, p++)
  233. {
  234. if (PlaneEqual (p, normal, dist))
  235. {
  236. mapplaneusers[i]++;
  237. return i;
  238. } //end if
  239. } //end for
  240. i = CreateNewFloatPlane (normal, dist);
  241. mapplaneusers[i]++;
  242. return i;
  243. } //end of the function FindFloatPlane
  244. #else
  245. int FindFloatPlane (vec3_t normal, vec_t dist)
  246. {
  247. int i;
  248. plane_t *p;
  249. int hash, h;
  250. SnapPlane (normal, &dist);
  251. hash = (int)fabs(dist) / 8;
  252. hash &= (PLANE_HASHES-1);
  253. // search the border bins as well
  254. for (i = -1; i <= 1; i++)
  255. {
  256. h = (hash+i)&(PLANE_HASHES-1);
  257. for (p = planehash[h]; p; p = p->hash_chain)
  258. {
  259. if (PlaneEqual(p, normal, dist))
  260. {
  261. mapplaneusers[p-mapplanes]++;
  262. return p - mapplanes;
  263. } //end if
  264. } //end for
  265. } //end for
  266. i = CreateNewFloatPlane (normal, dist);
  267. mapplaneusers[i]++;
  268. return i;
  269. } //end of the function FindFloatPlane
  270. #endif
  271. //===========================================================================
  272. //
  273. // Parameter: -
  274. // Returns: -
  275. // Changes Globals: -
  276. //===========================================================================
  277. int PlaneFromPoints (int *p0, int *p1, int *p2)
  278. {
  279. vec3_t t1, t2, normal;
  280. vec_t dist;
  281. VectorSubtract (p0, p1, t1);
  282. VectorSubtract (p2, p1, t2);
  283. CrossProduct (t1, t2, normal);
  284. VectorNormalize (normal);
  285. dist = DotProduct (p0, normal);
  286. return FindFloatPlane (normal, dist);
  287. } //end of the function PlaneFromPoints
  288. //===========================================================================
  289. // Adds any additional planes necessary to allow the brush to be expanded
  290. // against axial bounding boxes
  291. //
  292. // Parameter: -
  293. // Returns: -
  294. // Changes Globals: -
  295. //===========================================================================
  296. void AddBrushBevels (mapbrush_t *b)
  297. {
  298. int axis, dir;
  299. int i, j, k, l, order;
  300. side_t sidetemp;
  301. brush_texture_t tdtemp;
  302. #ifdef SIN
  303. textureref_t trtemp;
  304. #endif
  305. side_t *s, *s2;
  306. vec3_t normal;
  307. float dist;
  308. winding_t *w, *w2;
  309. vec3_t vec, vec2;
  310. float d;
  311. //
  312. // add the axial planes
  313. //
  314. order = 0;
  315. for (axis=0 ; axis <3 ; axis++)
  316. {
  317. for (dir=-1 ; dir <= 1 ; dir+=2, order++)
  318. {
  319. // see if the plane is allready present
  320. for (i=0, s=b->original_sides ; i<b->numsides ; i++,s++)
  321. {
  322. if (mapplanes[s->planenum].normal[axis] == dir)
  323. break;
  324. }
  325. if (i == b->numsides)
  326. { // add a new side
  327. if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
  328. Error ("MAX_MAP_BRUSHSIDES");
  329. nummapbrushsides++;
  330. b->numsides++;
  331. VectorClear (normal);
  332. normal[axis] = dir;
  333. if (dir == 1)
  334. dist = b->maxs[axis];
  335. else
  336. dist = -b->mins[axis];
  337. s->planenum = FindFloatPlane (normal, dist);
  338. s->texinfo = b->original_sides[0].texinfo;
  339. #ifdef SIN
  340. s->lightinfo = b->original_sides[0].lightinfo;
  341. #endif
  342. s->contents = b->original_sides[0].contents;
  343. s->flags |= SFL_BEVEL;
  344. c_boxbevels++;
  345. }
  346. // if the plane is not in it canonical order, swap it
  347. if (i != order)
  348. {
  349. sidetemp = b->original_sides[order];
  350. b->original_sides[order] = b->original_sides[i];
  351. b->original_sides[i] = sidetemp;
  352. j = b->original_sides - brushsides;
  353. tdtemp = side_brushtextures[j+order];
  354. side_brushtextures[j+order] = side_brushtextures[j+i];
  355. side_brushtextures[j+i] = tdtemp;
  356. #ifdef SIN
  357. trtemp = side_newrefs[j+order];
  358. side_newrefs[j+order] = side_newrefs[j+i];
  359. side_newrefs[j+i] = trtemp;
  360. #endif
  361. }
  362. }
  363. }
  364. //
  365. // add the edge bevels
  366. //
  367. if (b->numsides == 6)
  368. return; // pure axial
  369. // test the non-axial plane edges
  370. for (i=6 ; i<b->numsides ; i++)
  371. {
  372. s = b->original_sides + i;
  373. w = s->winding;
  374. if (!w)
  375. continue;
  376. for (j=0 ; j<w->numpoints ; j++)
  377. {
  378. k = (j+1)%w->numpoints;
  379. VectorSubtract (w->p[j], w->p[k], vec);
  380. if (VectorNormalize (vec) < 0.5)
  381. continue;
  382. SnapVector (vec);
  383. for (k=0 ; k<3 ; k++)
  384. if ( vec[k] == -1 || vec[k] == 1)
  385. break; // axial
  386. if (k != 3)
  387. continue; // only test non-axial edges
  388. // try the six possible slanted axials from this edge
  389. for (axis=0 ; axis <3 ; axis++)
  390. {
  391. for (dir=-1 ; dir <= 1 ; dir+=2)
  392. {
  393. // construct a plane
  394. VectorClear (vec2);
  395. vec2[axis] = dir;
  396. CrossProduct (vec, vec2, normal);
  397. if (VectorNormalize (normal) < 0.5)
  398. continue;
  399. dist = DotProduct (w->p[j], normal);
  400. // if all the points on all the sides are
  401. // behind this plane, it is a proper edge bevel
  402. for (k=0 ; k<b->numsides ; k++)
  403. {
  404. // if this plane has allready been used, skip it
  405. if (PlaneEqual (&mapplanes[b->original_sides[k].planenum]
  406. , normal, dist) )
  407. break;
  408. w2 = b->original_sides[k].winding;
  409. if (!w2)
  410. continue;
  411. for (l=0 ; l<w2->numpoints ; l++)
  412. {
  413. d = DotProduct (w2->p[l], normal) - dist;
  414. if (d > 0.1)
  415. break; // point in front
  416. }
  417. if (l != w2->numpoints)
  418. break;
  419. }
  420. if (k != b->numsides)
  421. continue; // wasn't part of the outer hull
  422. // add this plane
  423. if (nummapbrushsides == MAX_MAP_BRUSHSIDES)
  424. Error ("MAX_MAP_BRUSHSIDES");
  425. nummapbrushsides++;
  426. s2 = &b->original_sides[b->numsides];
  427. s2->planenum = FindFloatPlane (normal, dist);
  428. s2->texinfo = b->original_sides[0].texinfo;
  429. #ifdef SIN
  430. s2->lightinfo = b->original_sides[0].lightinfo;
  431. #endif
  432. s2->contents = b->original_sides[0].contents;
  433. s2->flags |= SFL_BEVEL;
  434. c_edgebevels++;
  435. b->numsides++;
  436. }
  437. }
  438. }
  439. }
  440. } //end of the function AddBrushBevels
  441. //===========================================================================
  442. // creates windigs for sides and mins / maxs for the brush
  443. //
  444. // Parameter: -
  445. // Returns: -
  446. // Changes Globals: -
  447. //===========================================================================
  448. qboolean MakeBrushWindings(mapbrush_t *ob)
  449. {
  450. int i, j;
  451. winding_t *w;
  452. side_t *side;
  453. plane_t *plane;
  454. ClearBounds (ob->mins, ob->maxs);
  455. for (i = 0; i < ob->numsides; i++)
  456. {
  457. plane = &mapplanes[ob->original_sides[i].planenum];
  458. w = BaseWindingForPlane(plane->normal, plane->dist);
  459. for (j = 0; j <ob->numsides && w; j++)
  460. {
  461. if (i == j) continue;
  462. if (ob->original_sides[j].flags & SFL_BEVEL) continue;
  463. plane = &mapplanes[ob->original_sides[j].planenum^1];
  464. ChopWindingInPlace(&w, plane->normal, plane->dist, 0); //CLIP_EPSILON);
  465. }
  466. side = &ob->original_sides[i];
  467. side->winding = w;
  468. if (w)
  469. {
  470. side->flags |= SFL_VISIBLE;
  471. for (j = 0; j < w->numpoints; j++)
  472. AddPointToBounds (w->p[j], ob->mins, ob->maxs);
  473. }
  474. }
  475. for (i = 0; i < 3; i++)
  476. {
  477. //IDBUG: all the indexes into the mins and maxs were zero (not using i)
  478. if (ob->mins[i] < -MAX_MAP_BOUNDS || ob->maxs[i] > MAX_MAP_BOUNDS)
  479. {
  480. Log_Print("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum);
  481. ob->numsides = 0; //remove the brush
  482. break;
  483. } //end if
  484. if (ob->mins[i] > MAX_MAP_BOUNDS || ob->maxs[i] < -MAX_MAP_BOUNDS)
  485. {
  486. Log_Print("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum);
  487. ob->numsides = 0; //remove the brush
  488. break;
  489. } //end if
  490. } //end for
  491. return true;
  492. } //end of the function MakeBrushWindings
  493. //===========================================================================
  494. // FIXME: currently doesn't mark all bevels
  495. // NOTE: when one brush bevel is found the remaining sides of the brush
  496. // are bevels as well (when the brush isn't expanded for AAS :))
  497. //
  498. // Parameter: -
  499. // Returns: -
  500. // Changes Globals: -
  501. //===========================================================================
  502. void MarkBrushBevels(mapbrush_t *brush)
  503. {
  504. int i;
  505. int we;
  506. side_t *s;
  507. //check all the sides of the brush
  508. for (i = 0; i < brush->numsides; i++)
  509. {
  510. s = brush->original_sides + i;
  511. //if the side has no winding
  512. if (!s->winding)
  513. {
  514. Log_Write("MarkBrushBevels: brush %d no winding", brush->brushnum);
  515. s->flags |= SFL_BEVEL;
  516. } //end if
  517. //if the winding is tiny
  518. else if (WindingIsTiny(s->winding))
  519. {
  520. s->flags |= SFL_BEVEL;
  521. Log_Write("MarkBrushBevels: brush %d tiny winding", brush->brushnum);
  522. } //end else if
  523. //if the winding has errors
  524. else
  525. {
  526. we = WindingError(s->winding);
  527. if (we == WE_NOTENOUGHPOINTS
  528. || we == WE_SMALLAREA
  529. || we == WE_POINTBOGUSRANGE
  530. // || we == WE_NONCONVEX
  531. )
  532. {
  533. Log_Write("MarkBrushBevels: brush %d %s", brush->brushnum, WindingErrorString());
  534. s->flags |= SFL_BEVEL;
  535. } //end else if
  536. } //end else
  537. if (s->flags & SFL_BEVEL)
  538. {
  539. s->flags &= ~SFL_VISIBLE;
  540. //if the side has a valid plane
  541. if (s->planenum > 0 && s->planenum < nummapplanes)
  542. {
  543. //if it is an axial plane
  544. if (mapplanes[s->planenum].type < 3) c_boxbevels++;
  545. else c_edgebevels++;
  546. } //end if
  547. } //end if
  548. } //end for
  549. } //end of the function MarkBrushBevels
  550. //===========================================================================
  551. // returns true if the map brush already exists
  552. //
  553. // Parameter: -
  554. // Returns: -
  555. // Changes Globals: -
  556. //===========================================================================
  557. int BrushExists(mapbrush_t *brush)
  558. {
  559. int i, s1, s2;
  560. side_t *side1, *side2;
  561. mapbrush_t *brush1, *brush2;
  562. for (i = 0; i < nummapbrushes; i++)
  563. {
  564. brush1 = brush;
  565. brush2 = &mapbrushes[i];
  566. //compare the brushes
  567. if (brush1->entitynum != brush2->entitynum) continue;
  568. //if (brush1->contents != brush2->contents) continue;
  569. if (brush1->numsides != brush2->numsides) continue;
  570. for (s1 = 0; s1 < brush1->numsides; s1++)
  571. {
  572. side1 = brush1->original_sides + s1;
  573. //
  574. for (s2 = 0; s2 < brush2->numsides; s2++)
  575. {
  576. side2 = brush2->original_sides + s2;
  577. //
  578. if ((side1->planenum & ~1) == (side2->planenum & ~1)
  579. // && side1->texinfo == side2->texinfo
  580. // && side1->contents == side2->contents
  581. // && side1->surf == side2->surf
  582. ) break;
  583. } //end if
  584. if (s2 >= brush2->numsides) break;
  585. } //end for
  586. if (s1 >= brush1->numsides) return true;
  587. } //end for
  588. return false;
  589. } //end of the function BrushExists
  590. //===========================================================================
  591. //
  592. // Parameter: -
  593. // Returns: -
  594. // Changes Globals: -
  595. //===========================================================================
  596. qboolean WriteMapBrush(FILE *fp, mapbrush_t *brush, vec3_t origin)
  597. {
  598. int sn, rotate, shift[2], sv, tv, planenum, p1, i, j;
  599. float scale[2], originshift[2], ang1, ang2, newdist;
  600. vec3_t vecs[2], axis[2];
  601. map_texinfo_t *ti;
  602. winding_t *w;
  603. side_t *s;
  604. plane_t *plane;
  605. if (noliquids)
  606. {
  607. if (brush->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
  608. {
  609. return true;
  610. } //end if
  611. } //end if
  612. //if the brush has no contents
  613. if (!brush->contents) return true;
  614. //print the leading {
  615. if (fprintf(fp, " { //brush %d\n", brush->brushnum) < 0) return false;
  616. //write brush sides
  617. for (sn = 0; sn < brush->numsides; sn++)
  618. {
  619. s = brush->original_sides + sn;
  620. //don't write out bevels
  621. if (!(s->flags & SFL_BEVEL))
  622. {
  623. //if the entity has an origin set
  624. if (origin[0] || origin[1] || origin[2])
  625. {
  626. newdist = mapplanes[s->planenum].dist +
  627. DotProduct(mapplanes[s->planenum].normal, origin);
  628. planenum = FindFloatPlane(mapplanes[s->planenum].normal, newdist);
  629. } //end if
  630. else
  631. {
  632. planenum = s->planenum;
  633. } //end else
  634. //always take the first plane, then flip the points if necesary
  635. plane = &mapplanes[planenum & ~1];
  636. w = BaseWindingForPlane(plane->normal, plane->dist);
  637. //
  638. for (i = 0; i < 3; i++)
  639. {
  640. for (j = 0; j < 3; j++)
  641. {
  642. if (fabs(w->p[i][j]) < 0.2) w->p[i][j] = 0;
  643. else if (fabs((int)w->p[i][j] - w->p[i][j]) < 0.3) w->p[i][j] = (int) w->p[i][j];
  644. //w->p[i][j] = (int) (w->p[i][j] + 0.2);
  645. } //end for
  646. } //end for
  647. //three non-colinear points to define the plane
  648. if (planenum & 1) p1 = 1;
  649. else p1 = 0;
  650. if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[p1][0], (int)w->p[p1][1], (int)w->p[p1][2]) < 0) return false;
  651. if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[!p1][0], (int)w->p[!p1][1], (int)w->p[!p1][2]) < 0) return false;
  652. if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
  653. //free the winding
  654. FreeWinding(w);
  655. //
  656. if (s->texinfo == TEXINFO_NODE)
  657. {
  658. if (brush->contents & CONTENTS_PLAYERCLIP)
  659. {
  660. //player clip
  661. if (loadedmaptype == MAPTYPE_SIN)
  662. {
  663. if (fprintf(fp, "generic/misc/clip 0 0 0 1 1") < 0) return false;
  664. } //end if
  665. else if (loadedmaptype == MAPTYPE_QUAKE2)
  666. { //FIXME: don't always use e1u1
  667. if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
  668. } //end else
  669. else if (loadedmaptype == MAPTYPE_QUAKE3)
  670. {
  671. if (fprintf(fp, "e1u1/clip 0 0 0 1 1") < 0) return false;
  672. } //end else if
  673. else
  674. {
  675. if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
  676. } //end else
  677. } //end if
  678. else if (brush->contents == CONTENTS_MONSTERCLIP)
  679. {
  680. //monster clip
  681. if (loadedmaptype == MAPTYPE_SIN)
  682. {
  683. if (fprintf(fp, "generic/misc/monster 0 0 0 1 1") < 0) return false;
  684. } //end if
  685. else if (loadedmaptype == MAPTYPE_QUAKE2)
  686. {
  687. if (fprintf(fp, "e1u1/clip_mon 0 0 0 1 1") < 0) return false;
  688. } //end else
  689. else
  690. {
  691. if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
  692. } //end else
  693. } //end else
  694. else
  695. {
  696. if (fprintf(fp, "clip 0 0 0 1 1") < 0) return false;
  697. Log_Write("brush->contents = %d\n", brush->contents);
  698. } //end else
  699. } //end if
  700. else if (loadedmaptype == MAPTYPE_SIN && s->texinfo == 0)
  701. {
  702. if (brush->contents & CONTENTS_DUMMYFENCE)
  703. {
  704. if (fprintf(fp, "generic/misc/fence 0 0 0 1 1") < 0) return false;
  705. } //end if
  706. else if (brush->contents & CONTENTS_MIST)
  707. {
  708. if (fprintf(fp, "generic/misc/volumetric_base 0 0 0 1 1") < 0) return false;
  709. } //end if
  710. else //unknown so far
  711. {
  712. if (fprintf(fp, "generic/misc/red 0 0 0 1 1") < 0) return false;
  713. } //end else
  714. } //end if
  715. else if (loadedmaptype == MAPTYPE_QUAKE3)
  716. {
  717. //always use the same texture
  718. if (fprintf(fp, "e2u3/floor1_2 0 0 0 1 1 1 0 0") < 0) return false;
  719. } //end else if
  720. else
  721. {
  722. //*
  723. ti = &map_texinfo[s->texinfo];
  724. //the scaling of the texture
  725. scale[0] = 1 / VectorNormalize2(ti->vecs[0], vecs[0]);
  726. scale[1] = 1 / VectorNormalize2(ti->vecs[1], vecs[1]);
  727. //
  728. TextureAxisFromPlane(plane, axis[0], axis[1]);
  729. //calculate texture shift done by entity origin
  730. originshift[0] = DotProduct(origin, axis[0]);
  731. originshift[1] = DotProduct(origin, axis[1]);
  732. //the texture shift without origin shift
  733. shift[0] = ti->vecs[0][3] - originshift[0];
  734. shift[1] = ti->vecs[1][3] - originshift[1];
  735. //
  736. if (axis[0][0]) sv = 0;
  737. else if (axis[0][1]) sv = 1;
  738. else sv = 2;
  739. if (axis[1][0]) tv = 0;
  740. else if (axis[1][1]) tv = 1;
  741. else tv = 2;
  742. //calculate rotation of texture
  743. if (vecs[0][tv] == 0) ang1 = vecs[0][sv] > 0 ? 90.0 : -90.0;
  744. else ang1 = atan2(vecs[0][sv], vecs[0][tv]) * 180 / Q_PI;
  745. if (ang1 < 0) ang1 += 360;
  746. if (ang1 >= 360) ang1 -= 360;
  747. if (axis[0][tv] == 0) ang2 = axis[0][sv] > 0 ? 90.0 : -90.0;
  748. else ang2 = atan2(axis[0][sv], axis[0][tv]) * 180 / Q_PI;
  749. if (ang2 < 0) ang2 += 360;
  750. if (ang2 >= 360) ang2 -= 360;
  751. rotate = ang2 - ang1;
  752. if (rotate < 0) rotate += 360;
  753. if (rotate >= 360) rotate -= 360;
  754. //write the texture info
  755. if (fprintf(fp, "%s %d %d %d", ti->texture, shift[0], shift[1], rotate) < 0) return false;
  756. if (fabs(scale[0] - ((int) scale[0])) < 0.001)
  757. {
  758. if (fprintf(fp, " %d", (int) scale[0]) < 0) return false;
  759. } //end if
  760. else
  761. {
  762. if (fprintf(fp, " %4f", scale[0]) < 0) return false;
  763. } //end if
  764. if (fabs(scale[1] - ((int) scale[1])) < 0.001)
  765. {
  766. if (fprintf(fp, " %d", (int) scale[1]) < 0) return false;
  767. } //end if
  768. else
  769. {
  770. if (fprintf(fp, " %4f", scale[1]) < 0) return false;
  771. } //end else
  772. //write the extra brush side info
  773. if (loadedmaptype == MAPTYPE_QUAKE2)
  774. {
  775. if (fprintf(fp, " %ld %ld %ld", s->contents, ti->flags, ti->value) < 0) return false;
  776. } //end if
  777. //*/
  778. } //end else
  779. if (fprintf(fp, "\n") < 0) return false;
  780. } //end if
  781. } //end if
  782. if (fprintf(fp, " }\n") < 0) return false;
  783. c_writtenbrushes++;
  784. return true;
  785. } //end of the function WriteMapBrush
  786. //===========================================================================
  787. //
  788. // Parameter: -
  789. // Returns: -
  790. // Changes Globals: -
  791. //===========================================================================
  792. qboolean WriteOriginBrush(FILE *fp, vec3_t origin)
  793. {
  794. vec3_t normal;
  795. float dist;
  796. int i, s;
  797. winding_t *w;
  798. if (fprintf(fp, " {\n") < 0) return false;
  799. //
  800. for (i = 0; i < 3; i++)
  801. {
  802. for (s = -1; s <= 1; s += 2)
  803. {
  804. //
  805. VectorClear(normal);
  806. normal[i] = s;
  807. dist = origin[i] * s + 16;
  808. //
  809. w = BaseWindingForPlane(normal, dist);
  810. //three non-colinear points to define the plane
  811. if (fprintf(fp," ( %5i %5i %5i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]) < 0) return false;
  812. if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]) < 0) return false;
  813. if (fprintf(fp,"( %5i %5i %5i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]) < 0) return false;
  814. //free the winding
  815. FreeWinding(w);
  816. //write origin texture:
  817. // CONTENTS_ORIGIN = 16777216
  818. // SURF_NODRAW = 128
  819. if (loadedmaptype == MAPTYPE_SIN)
  820. {
  821. if (fprintf(fp, "generic/misc/origin 0 0 0 1 1") < 0) return false;
  822. } //end if
  823. else if (loadedmaptype == MAPTYPE_HALFLIFE)
  824. {
  825. if (fprintf(fp, "origin 0 0 0 1 1") < 0) return false;
  826. } //end if
  827. else
  828. {
  829. if (fprintf(fp, "e1u1/origin 0 0 0 1 1") < 0) return false;
  830. } //end else
  831. //Quake2 extra brush side info
  832. if (loadedmaptype == MAPTYPE_QUAKE2)
  833. {
  834. //if (fprintf(fp, " 16777216 128 0") < 0) return false;
  835. } //end if
  836. if (fprintf(fp, "\n") < 0) return false;
  837. } //end for
  838. } //end for
  839. if (fprintf(fp, " }\n") < 0) return false;
  840. c_writtenbrushes++;
  841. return true;
  842. } //end of the function WriteOriginBrush
  843. //===========================================================================
  844. //
  845. // Parameter: -
  846. // Returns: -
  847. // Changes Globals: -
  848. //===========================================================================
  849. mapbrush_t *GetAreaPortalBrush(entity_t *mapent)
  850. {
  851. int portalnum, bn;
  852. mapbrush_t *brush;
  853. //the area portal number
  854. portalnum = mapent->areaportalnum;
  855. //find the area portal brush in the world brushes
  856. for (bn = 0; bn < nummapbrushes && portalnum; bn++)
  857. {
  858. brush = &mapbrushes[bn];
  859. //must be in world entity
  860. if (brush->entitynum == 0)
  861. {
  862. if (brush->contents & CONTENTS_AREAPORTAL)
  863. {
  864. portalnum--;
  865. } //end if
  866. } //end if
  867. } //end for
  868. if (bn < nummapbrushes)
  869. {
  870. return brush;
  871. } //end if
  872. else
  873. {
  874. Log_Print("area portal %d brush not found\n", mapent->areaportalnum);
  875. return NULL;
  876. } //end else
  877. } //end of the function GetAreaPortalBrush
  878. //===========================================================================
  879. //
  880. // Parameter: -
  881. // Returns: -
  882. // Changes Globals: -
  883. //===========================================================================
  884. qboolean WriteMapFileSafe(FILE *fp)
  885. {
  886. char key[1024], value[1024];
  887. int i, bn, entitybrushes;
  888. epair_t *ep;
  889. mapbrush_t *brush;
  890. entity_t *mapent;
  891. //vec3_t vec_origin = {0, 0, 0};
  892. //
  893. if (fprintf(fp,"//=====================================================\n"
  894. "//\n"
  895. "// map file created with BSPC "BSPC_VERSION"\n"
  896. "//\n"
  897. "// BSPC is designed to decompile material in which you own the copyright\n"
  898. "// or have obtained permission to decompile from the copyright owner. Unless\n"
  899. "// you own the copyright or have permission to decompile from the copyright\n"
  900. "// owner, you may be violating copyright law and be subject to payment of\n"
  901. "// damages and other remedies. If you are uncertain about your rights, contact\n"
  902. "// your legal advisor.\n"
  903. "//\n") < 0) return false;
  904. if (loadedmaptype == MAPTYPE_SIN)
  905. {
  906. if (fprintf(fp,
  907. "// generic/misc/red is used for unknown textures\n") < 0) return false;
  908. } //end if
  909. if (fprintf(fp,"//\n"
  910. "//=====================================================\n") < 0) return false;
  911. //write out all the entities
  912. for (i = 0; i < num_entities; i++)
  913. {
  914. mapent = &entities[i];
  915. if (!mapent->epairs)
  916. {
  917. continue;
  918. } //end if
  919. if (fprintf(fp, "{\n") < 0) return false;
  920. //
  921. if (loadedmaptype == MAPTYPE_QUAKE3)
  922. {
  923. if (!stricmp(ValueForKey(mapent, "classname"), "light"))
  924. {
  925. SetKeyValue(mapent, "light", "10000");
  926. } //end if
  927. } //end if
  928. //write epairs
  929. for (ep = mapent->epairs; ep; ep = ep->next)
  930. {
  931. strcpy(key, ep->key);
  932. StripTrailing (key);
  933. strcpy(value, ep->value);
  934. StripTrailing(value);
  935. //
  936. if (loadedmaptype == MAPTYPE_QUAKE2 ||
  937. loadedmaptype == MAPTYPE_SIN)
  938. {
  939. //don't write an origin for BSP models
  940. if (mapent->modelnum >= 0 && !strcmp(key, "origin")) continue;
  941. } //end if
  942. //don't write BSP model numbers
  943. if (mapent->modelnum >= 0 && !strcmp(key, "model") && value[0] == '*') continue;
  944. //
  945. if (fprintf(fp, " \"%s\" \"%s\"\n", key, value) < 0) return false;
  946. } //end for
  947. //
  948. if (ValueForKey(mapent, "origin")) GetVectorForKey(mapent, "origin", mapent->origin);
  949. else mapent->origin[0] = mapent->origin[1] = mapent->origin[2] = 0;
  950. //if this is an area portal entity
  951. if (!strcmp("func_areaportal", ValueForKey(mapent, "classname")))
  952. {
  953. brush = GetAreaPortalBrush(mapent);
  954. if (!brush) return false;
  955. if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
  956. } //end if
  957. else
  958. {
  959. entitybrushes = false;
  960. //write brushes
  961. for (bn = 0; bn < nummapbrushes; bn++)
  962. {
  963. brush = &mapbrushes[bn];
  964. //if the brush is part of this entity
  965. if (brush->entitynum == i)
  966. {
  967. //don't write out area portal brushes in the world
  968. if (!((brush->contents & CONTENTS_AREAPORTAL) && brush->entitynum == 0))
  969. {
  970. /*
  971. if (!strcmp("func_door_rotating", ValueForKey(mapent, "classname")))
  972. {
  973. AAS_PositionFuncRotatingBrush(mapent, brush);
  974. if (!WriteMapBrush(fp, brush, vec_origin)) return false;
  975. } //end if
  976. else //*/
  977. {
  978. if (!WriteMapBrush(fp, brush, mapent->origin)) return false;
  979. } //end else
  980. entitybrushes = true;
  981. } //end if
  982. } //end if
  983. } //end for
  984. //if the entity had brushes
  985. if (entitybrushes)
  986. {
  987. //if the entity has an origin set
  988. if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2])
  989. {
  990. if (!WriteOriginBrush(fp, mapent->origin)) return false;
  991. } //end if
  992. } //end if
  993. } //end else
  994. if (fprintf(fp, "}\n") < 0) return false;
  995. } //end for
  996. if (fprintf(fp, "//total of %d brushes\n", c_writtenbrushes) < 0) return false;
  997. return true;
  998. } //end of the function WriteMapFileSafe
  999. //===========================================================================
  1000. //
  1001. // Parameter: -
  1002. // Returns: -
  1003. // Changes Globals: -
  1004. //===========================================================================
  1005. void WriteMapFile(char *filename)
  1006. {
  1007. FILE *fp;
  1008. double start_time;
  1009. c_writtenbrushes = 0;
  1010. //the time started
  1011. start_time = I_FloatTime();
  1012. //
  1013. Log_Print("writing %s\n", filename);
  1014. fp = fopen(filename, "wb");
  1015. if (!fp)
  1016. {
  1017. Log_Print("can't open %s\n", filename);
  1018. return;
  1019. } //end if
  1020. if (!WriteMapFileSafe(fp))
  1021. {
  1022. fclose(fp);
  1023. Log_Print("error writing map file %s\n", filename);
  1024. return;
  1025. } //end if
  1026. fclose(fp);
  1027. //display creation time
  1028. Log_Print("written %d brushes\n", c_writtenbrushes);
  1029. Log_Print("map file written in %5.0f seconds\n", I_FloatTime() - start_time);
  1030. } //end of the function WriteMapFile
  1031. //===========================================================================
  1032. //
  1033. // Parameter: -
  1034. // Returns: -
  1035. // Changes Globals: -
  1036. //===========================================================================
  1037. void PrintMapInfo(void)
  1038. {
  1039. Log_Print("\n");
  1040. Log_Print("%6i brushes\n", nummapbrushes);
  1041. Log_Print("%6i brush sides\n", nummapbrushsides);
  1042. // Log_Print("%6i clipbrushes\n", c_clipbrushes);
  1043. // Log_Print("%6i total sides\n", nummapbrushsides);
  1044. // Log_Print("%6i boxbevels\n", c_boxbevels);
  1045. // Log_Print("%6i edgebevels\n", c_edgebevels);
  1046. // Log_Print("%6i entities\n", num_entities);
  1047. // Log_Print("%6i planes\n", nummapplanes);
  1048. // Log_Print("%6i areaportals\n", c_areaportals);
  1049. // Log_Print("%6i squatt brushes\n", c_squattbrushes);
  1050. // Log_Print("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2],
  1051. // map_maxs[0],map_maxs[1],map_maxs[2]);
  1052. } //end of the function PrintMapInfo
  1053. //===========================================================================
  1054. //
  1055. // Parameter: -
  1056. // Returns: -
  1057. // Changes Globals: -
  1058. //===========================================================================
  1059. void ResetMapLoading(void)
  1060. {
  1061. int i;
  1062. epair_t *ep, *nextep;
  1063. Q2_ResetMapLoading();
  1064. Sin_ResetMapLoading();
  1065. //free all map brush side windings
  1066. for (i = 0; i < nummapbrushsides; i++)
  1067. {
  1068. if (brushsides[i].winding)
  1069. {
  1070. FreeWinding(brushsides[i].winding);
  1071. } //end for
  1072. } //end for
  1073. //reset regular stuff
  1074. nummapbrushes = 0;
  1075. memset(mapbrushes, 0, MAX_MAPFILE_BRUSHES * sizeof(mapbrush_t));
  1076. //
  1077. nummapbrushsides = 0;
  1078. memset(brushsides, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(side_t));
  1079. memset(side_brushtextures, 0, MAX_MAPFILE_BRUSHSIDES * sizeof(brush_texture_t));
  1080. //
  1081. nummapplanes = 0;
  1082. memset(mapplanes, 0, MAX_MAPFILE_PLANES * sizeof(plane_t));
  1083. //
  1084. memset(planehash, 0, PLANE_HASHES * sizeof(plane_t *));
  1085. //
  1086. memset(map_texinfo, 0, MAX_MAPFILE_TEXINFO * sizeof(map_texinfo_t));
  1087. map_numtexinfo = 0;
  1088. //
  1089. VectorClear(map_mins);
  1090. VectorClear(map_maxs);
  1091. //
  1092. c_boxbevels = 0;
  1093. c_edgebevels = 0;
  1094. c_areaportals = 0;
  1095. c_clipbrushes = 0;
  1096. c_writtenbrushes = 0;
  1097. //clear the entities
  1098. for (i = 0; i < num_entities; i++)
  1099. {
  1100. for (ep = entities[i].epairs; ep; ep = nextep)
  1101. {
  1102. nextep = ep->next;
  1103. FreeMemory(ep->key);
  1104. FreeMemory(ep->value);
  1105. FreeMemory(ep);
  1106. } //end for
  1107. } //end for
  1108. num_entities = 0;
  1109. memset(entities, 0, MAX_MAP_ENTITIES * sizeof(entity_t));
  1110. } //end of the function ResetMapLoading
  1111. //===========================================================================
  1112. //
  1113. // Parameter: -
  1114. // Returns: -
  1115. // Changes Globals: -
  1116. //===========================================================================
  1117. #ifndef Q1_BSPVERSION
  1118. #define Q1_BSPVERSION 29
  1119. #endif
  1120. #ifndef HL_BSPVERSION
  1121. #define HL_BSPVERSION 30
  1122. #endif
  1123. #define Q2_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
  1124. #define Q2_BSPVERSION 38
  1125. #define SINGAME_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'R') //RBSP
  1126. #define SINGAME_BSPVERSION 1
  1127. #define SIN_BSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') //IBSP
  1128. #define SIN_BSPVERSION 41
  1129. typedef struct
  1130. {
  1131. int ident;
  1132. int version;
  1133. } idheader_t;
  1134. int LoadMapFromBSP(struct quakefile_s *qf)
  1135. {
  1136. idheader_t idheader;
  1137. if (ReadQuakeFile(qf, &idheader, 0, sizeof(idheader_t)) != sizeof(idheader_t))
  1138. {
  1139. return false;
  1140. } //end if
  1141. idheader.ident = LittleLong(idheader.ident);
  1142. idheader.version = LittleLong(idheader.version);
  1143. //Quake3 BSP file
  1144. if (idheader.ident == Q3_BSP_IDENT && idheader.version == Q3_BSP_VERSION)
  1145. {
  1146. ResetMapLoading();
  1147. Q3_LoadMapFromBSP(qf);
  1148. Q3_FreeMaxBSP();
  1149. } //end if
  1150. //Quake2 BSP file
  1151. else if (idheader.ident == Q2_BSPHEADER && idheader.version == Q2_BSPVERSION)
  1152. {
  1153. ResetMapLoading();
  1154. Q2_AllocMaxBSP();
  1155. Q2_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
  1156. Q2_FreeMaxBSP();
  1157. } //endif
  1158. //Sin BSP file
  1159. else if ((idheader.ident == SIN_BSPHEADER && idheader.version == SIN_BSPVERSION) ||
  1160. //the dorks gave the same format another ident and verions
  1161. (idheader.ident == SINGAME_BSPHEADER && idheader.version == SINGAME_BSPVERSION))
  1162. {
  1163. ResetMapLoading();
  1164. Sin_AllocMaxBSP();
  1165. Sin_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
  1166. Sin_FreeMaxBSP();
  1167. } //end if
  1168. //the Quake1 bsp files don't have a ident only a version
  1169. else if (idheader.ident == Q1_BSPVERSION)
  1170. {
  1171. ResetMapLoading();
  1172. Q1_AllocMaxBSP();
  1173. Q1_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
  1174. Q1_FreeMaxBSP();
  1175. } //end if
  1176. //Half-Life also only uses a version number
  1177. else if (idheader.ident == HL_BSPVERSION)
  1178. {
  1179. ResetMapLoading();
  1180. HL_AllocMaxBSP();
  1181. HL_LoadMapFromBSP(qf->filename, qf->offset, qf->length);
  1182. HL_FreeMaxBSP();
  1183. } //end if
  1184. else
  1185. {
  1186. Error("unknown BSP format %c%c%c%c, version %d\n",
  1187. (idheader.ident & 0xFF),
  1188. ((idheader.ident >> 8) & 0xFF),
  1189. ((idheader.ident >> 16) & 0xFF),
  1190. ((idheader.ident >> 24) & 0xFF), idheader.version);
  1191. return false;
  1192. } //end if
  1193. //
  1194. return true;
  1195. } //end of the function LoadMapFromBSP