aas_create.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  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 "../botlib/aasfile.h"
  20. #include "aas_create.h"
  21. #include "aas_store.h"
  22. #include "aas_gsubdiv.h"
  23. #include "aas_facemerging.h"
  24. #include "aas_areamerging.h"
  25. #include "aas_edgemelting.h"
  26. #include "aas_prunenodes.h"
  27. #include "aas_cfg.h"
  28. #include "../game/surfaceflags.h"
  29. //#define AW_DEBUG
  30. //#define L_DEBUG
  31. #define AREAONFACESIDE(face, area) (face->frontarea != area)
  32. tmp_aas_t tmpaasworld;
  33. //===========================================================================
  34. //
  35. // Parameter: -
  36. // Returns: -
  37. // Changes Globals: -
  38. //===========================================================================
  39. void AAS_InitTmpAAS(void)
  40. {
  41. //tmp faces
  42. tmpaasworld.numfaces = 0;
  43. tmpaasworld.facenum = 0;
  44. tmpaasworld.faces = NULL;
  45. //tmp convex areas
  46. tmpaasworld.numareas = 0;
  47. tmpaasworld.areanum = 0;
  48. tmpaasworld.areas = NULL;
  49. //tmp nodes
  50. tmpaasworld.numnodes = 0;
  51. tmpaasworld.nodes = NULL;
  52. //
  53. tmpaasworld.nodebuffer = NULL;
  54. } //end of the function AAS_InitTmpAAS
  55. //===========================================================================
  56. //
  57. // Parameter: -
  58. // Returns: -
  59. // Changes Globals: -
  60. //===========================================================================
  61. void AAS_FreeTmpAAS(void)
  62. {
  63. tmp_face_t *f, *nextf;
  64. tmp_area_t *a, *nexta;
  65. tmp_nodebuf_t *nb, *nextnb;
  66. //free all the faces
  67. for (f = tmpaasworld.faces; f; f = nextf)
  68. {
  69. nextf = f->l_next;
  70. if (f->winding) FreeWinding(f->winding);
  71. FreeMemory(f);
  72. } //end if
  73. //free all tmp areas
  74. for (a = tmpaasworld.areas; a; a = nexta)
  75. {
  76. nexta = a->l_next;
  77. if (a->settings) FreeMemory(a->settings);
  78. FreeMemory(a);
  79. } //end for
  80. //free all the tmp nodes
  81. for (nb = tmpaasworld.nodebuffer; nb; nb = nextnb)
  82. {
  83. nextnb = nb->next;
  84. FreeMemory(nb);
  85. } //end for
  86. } //end of the function AAS_FreeTmpAAS
  87. //===========================================================================
  88. //
  89. // Parameter: -
  90. // Returns: -
  91. // Changes Globals: -
  92. //===========================================================================
  93. tmp_face_t *AAS_AllocTmpFace(void)
  94. {
  95. tmp_face_t *tmpface;
  96. tmpface = (tmp_face_t *) GetClearedMemory(sizeof(tmp_face_t));
  97. tmpface->num = tmpaasworld.facenum++;
  98. tmpface->l_prev = NULL;
  99. tmpface->l_next = tmpaasworld.faces;
  100. if (tmpaasworld.faces) tmpaasworld.faces->l_prev = tmpface;
  101. tmpaasworld.faces = tmpface;
  102. tmpaasworld.numfaces++;
  103. return tmpface;
  104. } //end of the function AAS_AllocTmpFace
  105. //===========================================================================
  106. //
  107. // Parameter: -
  108. // Returns: -
  109. // Changes Globals: -
  110. //===========================================================================
  111. void AAS_FreeTmpFace(tmp_face_t *tmpface)
  112. {
  113. if (tmpface->l_next) tmpface->l_next->l_prev = tmpface->l_prev;
  114. if (tmpface->l_prev) tmpface->l_prev->l_next = tmpface->l_next;
  115. else tmpaasworld.faces = tmpface->l_next;
  116. //free the winding
  117. if (tmpface->winding) FreeWinding(tmpface->winding);
  118. //free the face
  119. FreeMemory(tmpface);
  120. tmpaasworld.numfaces--;
  121. } //end of the function AAS_FreeTmpFace
  122. //===========================================================================
  123. //
  124. // Parameter: -
  125. // Returns: -
  126. // Changes Globals: -
  127. //===========================================================================
  128. tmp_area_t *AAS_AllocTmpArea(void)
  129. {
  130. tmp_area_t *tmparea;
  131. tmparea = (tmp_area_t *) GetClearedMemory(sizeof(tmp_area_t));
  132. tmparea->areanum = tmpaasworld.areanum++;
  133. tmparea->l_prev = NULL;
  134. tmparea->l_next = tmpaasworld.areas;
  135. if (tmpaasworld.areas) tmpaasworld.areas->l_prev = tmparea;
  136. tmpaasworld.areas = tmparea;
  137. tmpaasworld.numareas++;
  138. return tmparea;
  139. } //end of the function AAS_AllocTmpArea
  140. //===========================================================================
  141. //
  142. // Parameter: -
  143. // Returns: -
  144. // Changes Globals: -
  145. //===========================================================================
  146. void AAS_FreeTmpArea(tmp_area_t *tmparea)
  147. {
  148. if (tmparea->l_next) tmparea->l_next->l_prev = tmparea->l_prev;
  149. if (tmparea->l_prev) tmparea->l_prev->l_next = tmparea->l_next;
  150. else tmpaasworld.areas = tmparea->l_next;
  151. if (tmparea->settings) FreeMemory(tmparea->settings);
  152. FreeMemory(tmparea);
  153. tmpaasworld.numareas--;
  154. } //end of the function AAS_FreeTmpArea
  155. //===========================================================================
  156. //
  157. // Parameter: -
  158. // Returns: -
  159. // Changes Globals: -
  160. //===========================================================================
  161. tmp_node_t *AAS_AllocTmpNode(void)
  162. {
  163. tmp_nodebuf_t *nodebuf;
  164. if (!tmpaasworld.nodebuffer ||
  165. tmpaasworld.nodebuffer->numnodes >= NODEBUF_SIZE)
  166. {
  167. nodebuf = (tmp_nodebuf_t *) GetClearedMemory(sizeof(tmp_nodebuf_t));
  168. nodebuf->next = tmpaasworld.nodebuffer;
  169. nodebuf->numnodes = 0;
  170. tmpaasworld.nodebuffer = nodebuf;
  171. } //end if
  172. tmpaasworld.numnodes++;
  173. return &tmpaasworld.nodebuffer->nodes[tmpaasworld.nodebuffer->numnodes++];
  174. } //end of the function AAS_AllocTmpNode
  175. //===========================================================================
  176. //
  177. // Parameter: -
  178. // Returns: -
  179. // Changes Globals: -
  180. //===========================================================================
  181. void AAS_FreeTmpNode(tmp_node_t *tmpnode)
  182. {
  183. tmpaasworld.numnodes--;
  184. } //end of the function AAS_FreeTmpNode
  185. //===========================================================================
  186. // returns true if the face is a gap from the given side
  187. //
  188. // Parameter: -
  189. // Returns: -
  190. // Changes Globals: -
  191. //===========================================================================
  192. int AAS_GapFace(tmp_face_t *tmpface, int side)
  193. {
  194. vec3_t invgravity;
  195. //if the face is a solid or ground face it can't be a gap
  196. if (tmpface->faceflags & (FACE_GROUND | FACE_SOLID)) return 0;
  197. VectorCopy(cfg.phys_gravitydirection, invgravity);
  198. VectorInverse(invgravity);
  199. return (DotProduct(invgravity, mapplanes[tmpface->planenum ^ side].normal) > cfg.phys_maxsteepness);
  200. } //end of the function AAS_GapFace
  201. //===========================================================================
  202. // returns true if the face is a ground face
  203. //
  204. // Parameter: -
  205. // Returns: -
  206. // Changes Globals: -
  207. //===========================================================================
  208. int AAS_GroundFace(tmp_face_t *tmpface)
  209. {
  210. vec3_t invgravity;
  211. //must be a solid face
  212. if (!(tmpface->faceflags & FACE_SOLID)) return 0;
  213. VectorCopy(cfg.phys_gravitydirection, invgravity);
  214. VectorInverse(invgravity);
  215. return (DotProduct(invgravity, mapplanes[tmpface->planenum].normal) > cfg.phys_maxsteepness);
  216. } //end of the function AAS_GroundFace
  217. //===========================================================================
  218. // adds the side of a face to an area
  219. //
  220. // side : 0 = front side
  221. // 1 = back side
  222. //
  223. // Parameter: -
  224. // Returns: -
  225. // Changes Globals: -
  226. //===========================================================================
  227. void AAS_AddFaceSideToArea(tmp_face_t *tmpface, int side, tmp_area_t *tmparea)
  228. {
  229. int tmpfaceside;
  230. if (side)
  231. {
  232. if (tmpface->backarea) Error("AAS_AddFaceSideToArea: already a back area\n");
  233. } //end if
  234. else
  235. {
  236. if (tmpface->frontarea) Error("AAS_AddFaceSideToArea: already a front area\n");
  237. } //end else
  238. if (side) tmpface->backarea = tmparea;
  239. else tmpface->frontarea = tmparea;
  240. if (tmparea->tmpfaces)
  241. {
  242. tmpfaceside = tmparea->tmpfaces->frontarea != tmparea;
  243. tmparea->tmpfaces->prev[tmpfaceside] = tmpface;
  244. } //end if
  245. tmpface->next[side] = tmparea->tmpfaces;
  246. tmpface->prev[side] = NULL;
  247. tmparea->tmpfaces = tmpface;
  248. } //end of the function AAS_AddFaceSideToArea
  249. //===========================================================================
  250. // remove (a side of) a face from an area
  251. //
  252. // Parameter: -
  253. // Returns: -
  254. // Changes Globals: -
  255. //===========================================================================
  256. void AAS_RemoveFaceFromArea(tmp_face_t *tmpface, tmp_area_t *tmparea)
  257. {
  258. int side, prevside, nextside;
  259. if (tmpface->frontarea != tmparea &&
  260. tmpface->backarea != tmparea)
  261. {
  262. Error("AAS_RemoveFaceFromArea: face not part of the area");
  263. } //end if
  264. side = tmpface->frontarea != tmparea;
  265. if (tmpface->prev[side])
  266. {
  267. prevside = tmpface->prev[side]->frontarea != tmparea;
  268. tmpface->prev[side]->next[prevside] = tmpface->next[side];
  269. } //end if
  270. else
  271. {
  272. tmparea->tmpfaces = tmpface->next[side];
  273. } //end else
  274. if (tmpface->next[side])
  275. {
  276. nextside = tmpface->next[side]->frontarea != tmparea;
  277. tmpface->next[side]->prev[nextside] = tmpface->prev[side];
  278. } //end if
  279. //remove the area number from the face depending on the side
  280. if (side) tmpface->backarea = NULL;
  281. else tmpface->frontarea = NULL;
  282. tmpface->prev[side] = NULL;
  283. tmpface->next[side] = NULL;
  284. } //end of the function AAS_RemoveFaceFromArea
  285. //===========================================================================
  286. //
  287. // Parameter: -
  288. // Returns: -
  289. // Changes Globals: -
  290. //===========================================================================
  291. void AAS_CheckArea(tmp_area_t *tmparea)
  292. {
  293. int side;
  294. tmp_face_t *face;
  295. plane_t *plane;
  296. vec3_t wcenter, acenter = {0, 0, 0};
  297. vec3_t normal;
  298. float n, dist;
  299. if (tmparea->invalid) Log_Print("AAS_CheckArea: invalid area\n");
  300. for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
  301. {
  302. //side of the face the area is on
  303. side = face->frontarea != tmparea;
  304. WindingCenter(face->winding, wcenter);
  305. VectorAdd(acenter, wcenter, acenter);
  306. n++;
  307. } //end for
  308. n = 1 / n;
  309. VectorScale(acenter, n, acenter);
  310. for (face = tmparea->tmpfaces; face; face = face->next[side])
  311. {
  312. //side of the face the area is on
  313. side = face->frontarea != tmparea;
  314. #ifdef L_DEBUG
  315. if (WindingError(face->winding))
  316. {
  317. Log_Write("AAS_CheckArea: area %d face %d: %s\r\n", tmparea->areanum,
  318. face->num, WindingErrorString());
  319. } //end if
  320. #endif L_DEBUG
  321. plane = &mapplanes[face->planenum ^ side];
  322. if (DotProduct(plane->normal, acenter) - plane->dist < 0)
  323. {
  324. Log_Print("AAS_CheckArea: area %d face %d is flipped\n", tmparea->areanum, face->num);
  325. Log_Print("AAS_CheckArea: area %d center is %f %f %f\n", tmparea->areanum, acenter[0], acenter[1], acenter[2]);
  326. } //end if
  327. //check if the winding plane is the same as the face plane
  328. WindingPlane(face->winding, normal, &dist);
  329. plane = &mapplanes[face->planenum];
  330. #ifdef L_DEBUG
  331. if (fabs(dist - plane->dist) > 0.4 ||
  332. fabs(normal[0] - plane->normal[0]) > 0.0001 ||
  333. fabs(normal[1] - plane->normal[1]) > 0.0001 ||
  334. fabs(normal[2] - plane->normal[2]) > 0.0001)
  335. {
  336. Log_Write("AAS_CheckArea: area %d face %d winding plane unequal to face plane\r\n",
  337. tmparea->areanum, face->num);
  338. } //end if
  339. #endif L_DEBUG
  340. } //end for
  341. } //end of the function AAS_CheckArea
  342. //===========================================================================
  343. //
  344. // Parameter: -
  345. // Returns: -
  346. // Changes Globals: -
  347. //===========================================================================
  348. void AAS_CheckFaceWindingPlane(tmp_face_t *face)
  349. {
  350. float dist, sign1, sign2;
  351. vec3_t normal;
  352. plane_t *plane;
  353. winding_t *w;
  354. //check if the winding plane is the same as the face plane
  355. WindingPlane(face->winding, normal, &dist);
  356. plane = &mapplanes[face->planenum];
  357. //
  358. sign1 = DotProduct(plane->normal, normal);
  359. //
  360. if (fabs(dist - plane->dist) > 0.4 ||
  361. fabs(normal[0] - plane->normal[0]) > 0.0001 ||
  362. fabs(normal[1] - plane->normal[1]) > 0.0001 ||
  363. fabs(normal[2] - plane->normal[2]) > 0.0001)
  364. {
  365. VectorInverse(normal);
  366. dist = -dist;
  367. if (fabs(dist - plane->dist) > 0.4 ||
  368. fabs(normal[0] - plane->normal[0]) > 0.0001 ||
  369. fabs(normal[1] - plane->normal[1]) > 0.0001 ||
  370. fabs(normal[2] - plane->normal[2]) > 0.0001)
  371. {
  372. Log_Write("AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n",
  373. face->num);
  374. //
  375. sign2 = DotProduct(plane->normal, normal);
  376. if ((sign1 < 0 && sign2 > 0) ||
  377. (sign1 > 0 && sign2 < 0))
  378. {
  379. Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
  380. face->num);
  381. w = face->winding;
  382. face->winding = ReverseWinding(w);
  383. FreeWinding(w);
  384. } //end if
  385. } //end if
  386. else
  387. {
  388. Log_Write("AAS_CheckFaceWindingPlane: face %d winding reversed\r\n",
  389. face->num);
  390. w = face->winding;
  391. face->winding = ReverseWinding(w);
  392. FreeWinding(w);
  393. } //end else
  394. } //end if
  395. } //end of the function AAS_CheckFaceWindingPlane
  396. //===========================================================================
  397. //
  398. // Parameter: -
  399. // Returns: -
  400. // Changes Globals: -
  401. //===========================================================================
  402. void AAS_CheckAreaWindingPlanes(void)
  403. {
  404. int side;
  405. tmp_area_t *tmparea;
  406. tmp_face_t *face;
  407. Log_Write("AAS_CheckAreaWindingPlanes:\r\n");
  408. for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
  409. {
  410. if (tmparea->invalid) continue;
  411. for (face = tmparea->tmpfaces; face; face = face->next[side])
  412. {
  413. side = face->frontarea != tmparea;
  414. AAS_CheckFaceWindingPlane(face);
  415. } //end for
  416. } //end for
  417. } //end of the function AAS_CheckAreaWindingPlanes
  418. //===========================================================================
  419. //
  420. // Parameter: -
  421. // Returns: -
  422. // Changes Globals: -
  423. //===========================================================================
  424. void AAS_FlipAreaFaces(tmp_area_t *tmparea)
  425. {
  426. int side;
  427. tmp_face_t *face;
  428. plane_t *plane;
  429. vec3_t wcenter, acenter = {0, 0, 0};
  430. //winding_t *w;
  431. float n;
  432. for (n = 0, face = tmparea->tmpfaces; face; face = face->next[side])
  433. {
  434. if (!face->frontarea) Error("face %d has no front area\n", face->num);
  435. //side of the face the area is on
  436. side = face->frontarea != tmparea;
  437. WindingCenter(face->winding, wcenter);
  438. VectorAdd(acenter, wcenter, acenter);
  439. n++;
  440. } //end for
  441. n = 1 / n;
  442. VectorScale(acenter, n, acenter);
  443. for (face = tmparea->tmpfaces; face; face = face->next[side])
  444. {
  445. //side of the face the area is on
  446. side = face->frontarea != tmparea;
  447. plane = &mapplanes[face->planenum ^ side];
  448. if (DotProduct(plane->normal, acenter) - plane->dist < 0)
  449. {
  450. Log_Print("area %d face %d flipped: front area %d, back area %d\n", tmparea->areanum, face->num,
  451. face->frontarea ? face->frontarea->areanum : 0,
  452. face->backarea ? face->backarea->areanum : 0);
  453. /*
  454. face->planenum = face->planenum ^ 1;
  455. w = face->winding;
  456. face->winding = ReverseWinding(w);
  457. FreeWinding(w);
  458. */
  459. } //end if
  460. #ifdef L_DEBUG
  461. {
  462. float dist;
  463. vec3_t normal;
  464. //check if the winding plane is the same as the face plane
  465. WindingPlane(face->winding, normal, &dist);
  466. plane = &mapplanes[face->planenum];
  467. if (fabs(dist - plane->dist) > 0.4 ||
  468. fabs(normal[0] - plane->normal[0]) > 0.0001 ||
  469. fabs(normal[1] - plane->normal[1]) > 0.0001 ||
  470. fabs(normal[2] - plane->normal[2]) > 0.0001)
  471. {
  472. Log_Write("area %d face %d winding plane unequal to face plane\r\n",
  473. tmparea->areanum, face->num);
  474. } //end if
  475. }
  476. #endif
  477. } //end for
  478. } //end of the function AAS_FlipAreaFaces
  479. //===========================================================================
  480. //
  481. // Parameter: -
  482. // Returns: -
  483. // Changes Globals: -
  484. //===========================================================================
  485. void AAS_RemoveAreaFaceColinearPoints(void)
  486. {
  487. int side;
  488. tmp_face_t *face;
  489. tmp_area_t *tmparea;
  490. //FIXME: loop over the faces instead of area->faces
  491. for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
  492. {
  493. for (face = tmparea->tmpfaces; face; face = face->next[side])
  494. {
  495. side = face->frontarea != tmparea;
  496. RemoveColinearPoints(face->winding);
  497. // RemoveEqualPoints(face->winding, 0.1);
  498. } //end for
  499. } //end for
  500. } //end of the function AAS_RemoveAreaFaceColinearPoints
  501. //===========================================================================
  502. //
  503. // Parameter: -
  504. // Returns: -
  505. // Changes Globals: -
  506. //===========================================================================
  507. void AAS_RemoveTinyFaces(void)
  508. {
  509. int side, num;
  510. tmp_face_t *face, *nextface;
  511. tmp_area_t *tmparea;
  512. //FIXME: loop over the faces instead of area->faces
  513. Log_Write("AAS_RemoveTinyFaces\r\n");
  514. num = 0;
  515. for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
  516. {
  517. for (face = tmparea->tmpfaces; face; face = nextface)
  518. {
  519. side = face->frontarea != tmparea;
  520. nextface = face->next[side];
  521. //
  522. if (WindingArea(face->winding) < 1)
  523. {
  524. if (face->frontarea) AAS_RemoveFaceFromArea(face, face->frontarea);
  525. if (face->backarea) AAS_RemoveFaceFromArea(face, face->backarea);
  526. AAS_FreeTmpFace(face);
  527. //Log_Write("area %d face %d is tiny\r\n", tmparea->areanum, face->num);
  528. num++;
  529. } //end if
  530. } //end for
  531. } //end for
  532. Log_Write("%d tiny faces removed\r\n", num);
  533. } //end of the function AAS_RemoveTinyFaces
  534. //===========================================================================
  535. //
  536. // Parameter: -
  537. // Returns: -
  538. // Changes Globals: -
  539. //===========================================================================
  540. void AAS_CreateAreaSettings(void)
  541. {
  542. int i, flags, side, numgrounded, numladderareas, numliquidareas;
  543. tmp_face_t *face;
  544. tmp_area_t *tmparea;
  545. numgrounded = 0;
  546. numladderareas = 0;
  547. numliquidareas = 0;
  548. Log_Write("AAS_CreateAreaSettings\r\n");
  549. i = 0;
  550. qprintf("%6d areas provided with settings", i);
  551. for (tmparea = tmpaasworld.areas; tmparea; tmparea = tmparea->l_next)
  552. {
  553. //if the area is invalid there no need to create settings for it
  554. if (tmparea->invalid) continue;
  555. tmparea->settings = (tmp_areasettings_t *) GetClearedMemory(sizeof(tmp_areasettings_t));
  556. tmparea->settings->contents = tmparea->contents;
  557. tmparea->settings->modelnum = tmparea->modelnum;
  558. flags = 0;
  559. for (face = tmparea->tmpfaces; face; face = face->next[side])
  560. {
  561. side = face->frontarea != tmparea;
  562. flags |= face->faceflags;
  563. } //end for
  564. tmparea->settings->areaflags = 0;
  565. if (flags & FACE_GROUND)
  566. {
  567. tmparea->settings->areaflags |= AREA_GROUNDED;
  568. numgrounded++;
  569. } //end if
  570. if (flags & FACE_LADDER)
  571. {
  572. tmparea->settings->areaflags |= AREA_LADDER;
  573. numladderareas++;
  574. } //end if
  575. if (tmparea->contents & (AREACONTENTS_WATER |
  576. AREACONTENTS_SLIME |
  577. AREACONTENTS_LAVA))
  578. {
  579. tmparea->settings->areaflags |= AREA_LIQUID;
  580. numliquidareas++;
  581. } //end if
  582. //presence type of the area
  583. tmparea->settings->presencetype = tmparea->presencetype;
  584. //
  585. qprintf("\r%6d", ++i);
  586. } //end for
  587. qprintf("\n");
  588. #ifdef AASINFO
  589. Log_Print("%6d grounded areas\n", numgrounded);
  590. Log_Print("%6d ladder areas\n", numladderareas);
  591. Log_Print("%6d liquid areas\n", numliquidareas);
  592. #endif //AASINFO
  593. } //end of the function AAS_CreateAreaSettings
  594. //===========================================================================
  595. // create a tmp AAS area from a leaf node
  596. //
  597. // Parameter: -
  598. // Returns: -
  599. // Changes Globals: -
  600. //===========================================================================
  601. tmp_node_t *AAS_CreateArea(node_t *node)
  602. {
  603. int pside;
  604. int areafaceflags;
  605. portal_t *p;
  606. tmp_face_t *tmpface;
  607. tmp_area_t *tmparea;
  608. tmp_node_t *tmpnode;
  609. vec3_t up = {0, 0, 1};
  610. //create an area from this leaf
  611. tmparea = AAS_AllocTmpArea();
  612. tmparea->tmpfaces = NULL;
  613. //clear the area face flags
  614. areafaceflags = 0;
  615. //make aas faces from the portals
  616. for (p = node->portals; p; p = p->next[pside])
  617. {
  618. pside = (p->nodes[1] == node);
  619. //don't create faces from very small portals
  620. // if (WindingArea(p->winding) < 1) continue;
  621. //if there's already a face created for this portal
  622. if (p->tmpface)
  623. {
  624. //add the back side of the face to the area
  625. AAS_AddFaceSideToArea(p->tmpface, 1, tmparea);
  626. } //end if
  627. else
  628. {
  629. tmpface = AAS_AllocTmpFace();
  630. //set the face pointer at the portal so we can see from
  631. //the portal there's a face created for it
  632. p->tmpface = tmpface;
  633. //FIXME: test this change
  634. //tmpface->planenum = (p->planenum & ~1) | pside;
  635. tmpface->planenum = p->planenum ^ pside;
  636. if (pside) tmpface->winding = ReverseWinding(p->winding);
  637. else tmpface->winding = CopyWinding(p->winding);
  638. #ifdef L_DEBUG
  639. //
  640. AAS_CheckFaceWindingPlane(tmpface);
  641. #endif //L_DEBUG
  642. //if there's solid at the other side of the portal
  643. if (p->nodes[!pside]->contents & (CONTENTS_SOLID | CONTENTS_PLAYERCLIP))
  644. {
  645. tmpface->faceflags |= FACE_SOLID;
  646. } //end if
  647. //else there is no solid at the other side and if there
  648. //is a liquid at this side
  649. else if (node->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA))
  650. {
  651. tmpface->faceflags |= FACE_LIQUID;
  652. //if there's no liquid at the other side
  653. if (!(p->nodes[!pside]->contents & (CONTENTS_WATER|CONTENTS_SLIME|CONTENTS_LAVA)))
  654. {
  655. tmpface->faceflags |= FACE_LIQUIDSURFACE;
  656. } //end if
  657. } //end else
  658. //if there's ladder contents at other side of the portal
  659. if ((p->nodes[pside]->contents & CONTENTS_LADDER) ||
  660. (p->nodes[!pside]->contents & CONTENTS_LADDER))
  661. {
  662. //NOTE: doesn't have to be solid at the other side because
  663. // when standing one can use a crouch area (which is not solid)
  664. // as a ladder
  665. // imagine a ladder one can walk underthrough,
  666. // under the ladder against the ladder is a crouch area
  667. // the (vertical) sides of this crouch area area also used as
  668. // ladder sides when standing (not crouched)
  669. tmpface->faceflags |= FACE_LADDER;
  670. } //end if
  671. //if it is possible to stand on the face
  672. if (AAS_GroundFace(tmpface))
  673. {
  674. tmpface->faceflags |= FACE_GROUND;
  675. } //end if
  676. //
  677. areafaceflags |= tmpface->faceflags;
  678. //no aas face number yet (zero is a dummy in the aasworld faces)
  679. tmpface->aasfacenum = 0;
  680. //add the front side of the face to the area
  681. AAS_AddFaceSideToArea(tmpface, 0, tmparea);
  682. } //end else
  683. } //end for
  684. qprintf("\r%6d", tmparea->areanum);
  685. //presence type in the area
  686. tmparea->presencetype = ~node->expansionbboxes & cfg.allpresencetypes;
  687. //
  688. tmparea->contents = 0;
  689. if (node->contents & CONTENTS_CLUSTERPORTAL) tmparea->contents |= AREACONTENTS_CLUSTERPORTAL;
  690. if (node->contents & CONTENTS_MOVER) tmparea->contents |= AREACONTENTS_MOVER;
  691. if (node->contents & CONTENTS_TELEPORTER) tmparea->contents |= AREACONTENTS_TELEPORTER;
  692. if (node->contents & CONTENTS_JUMPPAD) tmparea->contents |= AREACONTENTS_JUMPPAD;
  693. if (node->contents & CONTENTS_DONOTENTER) tmparea->contents |= AREACONTENTS_DONOTENTER;
  694. if (node->contents & CONTENTS_WATER) tmparea->contents |= AREACONTENTS_WATER;
  695. if (node->contents & CONTENTS_LAVA) tmparea->contents |= AREACONTENTS_LAVA;
  696. if (node->contents & CONTENTS_SLIME) tmparea->contents |= AREACONTENTS_SLIME;
  697. if (node->contents & CONTENTS_NOTTEAM1) tmparea->contents |= AREACONTENTS_NOTTEAM1;
  698. if (node->contents & CONTENTS_NOTTEAM2) tmparea->contents |= AREACONTENTS_NOTTEAM2;
  699. //store the bsp model that's inside this node
  700. tmparea->modelnum = node->modelnum;
  701. //sorta check for flipped area faces (remove??)
  702. AAS_FlipAreaFaces(tmparea);
  703. //check if the area is ok (remove??)
  704. AAS_CheckArea(tmparea);
  705. //
  706. tmpnode = AAS_AllocTmpNode();
  707. tmpnode->planenum = 0;
  708. tmpnode->children[0] = 0;
  709. tmpnode->children[1] = 0;
  710. tmpnode->tmparea = tmparea;
  711. //
  712. return tmpnode;
  713. } //end of the function AAS_CreateArea
  714. //===========================================================================
  715. //
  716. // Parameter: -
  717. // Returns: -
  718. // Changes Globals: -
  719. //===========================================================================
  720. tmp_node_t *AAS_CreateAreas_r(node_t *node)
  721. {
  722. tmp_node_t *tmpnode;
  723. //recurse down to leafs
  724. if (node->planenum != PLANENUM_LEAF)
  725. {
  726. //the first tmp node is a dummy
  727. tmpnode = AAS_AllocTmpNode();
  728. tmpnode->planenum = node->planenum;
  729. tmpnode->children[0] = AAS_CreateAreas_r(node->children[0]);
  730. tmpnode->children[1] = AAS_CreateAreas_r(node->children[1]);
  731. return tmpnode;
  732. } //end if
  733. //areas won't be created for solid leafs
  734. if (node->contents & CONTENTS_SOLID)
  735. {
  736. //just return zero for a solid leaf (in tmp AAS NULL is a solid leaf)
  737. return NULL;
  738. } //end if
  739. return AAS_CreateArea(node);
  740. } //end of the function AAS_CreateAreas_r
  741. //===========================================================================
  742. //
  743. // Parameter: -
  744. // Returns: -
  745. // Changes Globals: -
  746. //===========================================================================
  747. void AAS_CreateAreas(node_t *node)
  748. {
  749. Log_Write("AAS_CreateAreas\r\n");
  750. qprintf("%6d areas created", 0);
  751. tmpaasworld.nodes = AAS_CreateAreas_r(node);
  752. qprintf("\n");
  753. Log_Write("%6d areas created\r\n", tmpaasworld.numareas);
  754. } //end of the function AAS_CreateAreas
  755. //===========================================================================
  756. //
  757. // Parameter: -
  758. // Returns: -
  759. // Changes Globals: -
  760. //===========================================================================
  761. void AAS_PrintNumGroundFaces(void)
  762. {
  763. tmp_face_t *tmpface;
  764. int numgroundfaces = 0;
  765. for (tmpface = tmpaasworld.faces; tmpface; tmpface = tmpface->l_next)
  766. {
  767. if (tmpface->faceflags & FACE_GROUND)
  768. {
  769. numgroundfaces++;
  770. } //end if
  771. } //end for
  772. qprintf("%6d ground faces\n", numgroundfaces);
  773. } //end of the function AAS_PrintNumGroundFaces
  774. //===========================================================================
  775. // checks the number of shared faces between the given two areas
  776. // since areas are convex they should only have ONE shared face
  777. // however due to crappy face merging there are sometimes several
  778. // shared faces
  779. //
  780. // Parameter: -
  781. // Returns: -
  782. // Changes Globals: -
  783. //===========================================================================
  784. void AAS_CheckAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
  785. {
  786. int numsharedfaces, side;
  787. tmp_face_t *face1, *sharedface;
  788. if (tmparea1->invalid || tmparea2->invalid) return;
  789. sharedface = NULL;
  790. numsharedfaces = 0;
  791. for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
  792. {
  793. side = face1->frontarea != tmparea1;
  794. if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
  795. {
  796. sharedface = face1;
  797. numsharedfaces++;
  798. } //end if
  799. } //end if
  800. if (!sharedface) return;
  801. //the areas should only have one shared face
  802. if (numsharedfaces > 1)
  803. {
  804. Log_Write("---- tmp area %d and %d have %d shared faces\r\n",
  805. tmparea1->areanum, tmparea2->areanum, numsharedfaces);
  806. for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
  807. {
  808. side = face1->frontarea != tmparea1;
  809. if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
  810. {
  811. Log_Write("face %d, planenum = %d, face->frontarea = %d face->backarea = %d\r\n",
  812. face1->num, face1->planenum, face1->frontarea->areanum, face1->backarea->areanum);
  813. } //end if
  814. } //end if
  815. } //end if
  816. } //end of the function AAS_CheckAreaSharedFaces
  817. //===========================================================================
  818. //
  819. // Parameter: -
  820. // Returns: -
  821. // Changes Globals: -
  822. //===========================================================================
  823. void AAS_CheckSharedFaces(void)
  824. {
  825. tmp_area_t *tmparea1, *tmparea2;
  826. for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
  827. {
  828. for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
  829. {
  830. if (tmparea1 == tmparea2) continue;
  831. AAS_CheckAreaSharedFaces(tmparea1, tmparea2);
  832. } //end for
  833. } //end for
  834. } //end of the function AAS_CheckSharedFaces
  835. //===========================================================================
  836. //
  837. // Parameter: -
  838. // Returns: -
  839. // Changes Globals: -
  840. //===========================================================================
  841. void AAS_FlipFace(tmp_face_t *face)
  842. {
  843. tmp_area_t *frontarea, *backarea;
  844. winding_t *w;
  845. frontarea = face->frontarea;
  846. backarea = face->backarea;
  847. //must have an area at both sides before flipping is allowed
  848. if (!frontarea || !backarea) return;
  849. //flip the face winding
  850. w = face->winding;
  851. face->winding = ReverseWinding(w);
  852. FreeWinding(w);
  853. //flip the face plane
  854. face->planenum ^= 1;
  855. //flip the face areas
  856. AAS_RemoveFaceFromArea(face, frontarea);
  857. AAS_RemoveFaceFromArea(face, backarea);
  858. AAS_AddFaceSideToArea(face, 1, frontarea);
  859. AAS_AddFaceSideToArea(face, 0, backarea);
  860. } //end of the function AAS_FlipFace
  861. //===========================================================================
  862. //
  863. // Parameter: -
  864. // Returns: -
  865. // Changes Globals: -
  866. //===========================================================================
  867. /*
  868. void AAS_FlipAreaSharedFaces(tmp_area_t *tmparea1, tmp_area_t *tmparea2)
  869. {
  870. int numsharedfaces, side, area1facing, area2facing;
  871. tmp_face_t *face1, *sharedface;
  872. if (tmparea1->invalid || tmparea2->invalid) return;
  873. sharedface = NULL;
  874. numsharedfaces = 0;
  875. area1facing = 0; //number of shared faces facing towards area 1
  876. area2facing = 0; //number of shared faces facing towards area 2
  877. for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
  878. {
  879. side = face1->frontarea != tmparea1;
  880. if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
  881. {
  882. sharedface = face1;
  883. numsharedfaces++;
  884. if (face1->frontarea == tmparea1) area1facing++;
  885. else area2facing++;
  886. } //end if
  887. } //end if
  888. if (!sharedface) return;
  889. //if there's only one shared face
  890. if (numsharedfaces <= 1) return;
  891. //if all the shared faces are facing to the same area
  892. if (numsharedfaces == area1facing || numsharedfaces == area2facing) return;
  893. //
  894. do
  895. {
  896. for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side])
  897. {
  898. side = face1->frontarea != tmparea1;
  899. if (face1->backarea == tmparea2 || face1->frontarea == tmparea2)
  900. {
  901. if (face1->frontarea != tmparea1)
  902. {
  903. AAS_FlipFace(face1);
  904. break;
  905. } //end if
  906. } //end if
  907. } //end for
  908. } while(face1);
  909. } //end of the function AAS_FlipAreaSharedFaces
  910. //===========================================================================
  911. //
  912. // Parameter: -
  913. // Returns: -
  914. // Changes Globals: -
  915. //===========================================================================
  916. void AAS_FlipSharedFaces(void)
  917. {
  918. int i;
  919. tmp_area_t *tmparea1, *tmparea2;
  920. i = 0;
  921. qprintf("%6d areas checked for shared face flipping", i);
  922. for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
  923. {
  924. if (tmparea1->invalid) continue;
  925. for (tmparea2 = tmpaasworld.areas; tmparea2; tmparea2 = tmparea2->l_next)
  926. {
  927. if (tmparea2->invalid) continue;
  928. if (tmparea1 == tmparea2) continue;
  929. AAS_FlipAreaSharedFaces(tmparea1, tmparea2);
  930. } //end for
  931. qprintf("\r%6d", ++i);
  932. } //end for
  933. Log_Print("\r%6d areas checked for shared face flipping\n", i);
  934. } //end of the function AAS_FlipSharedFaces
  935. */
  936. //===========================================================================
  937. //
  938. // Parameter: -
  939. // Returns: -
  940. // Changes Globals: -
  941. //===========================================================================
  942. void AAS_FlipSharedFaces(void)
  943. {
  944. int i, side1, side2;
  945. tmp_area_t *tmparea1;
  946. tmp_face_t *face1, *face2;
  947. i = 0;
  948. qprintf("%6d areas checked for shared face flipping", i);
  949. for (tmparea1 = tmpaasworld.areas; tmparea1; tmparea1 = tmparea1->l_next)
  950. {
  951. if (tmparea1->invalid) continue;
  952. for (face1 = tmparea1->tmpfaces; face1; face1 = face1->next[side1])
  953. {
  954. side1 = face1->frontarea != tmparea1;
  955. if (!face1->frontarea || !face1->backarea) continue;
  956. //
  957. for (face2 = face1->next[side1]; face2; face2 = face2->next[side2])
  958. {
  959. side2 = face2->frontarea != tmparea1;
  960. if (!face2->frontarea || !face2->backarea) continue;
  961. //
  962. if (face1->frontarea == face2->backarea &&
  963. face1->backarea == face2->frontarea)
  964. {
  965. AAS_FlipFace(face2);
  966. } //end if
  967. //recheck side
  968. side2 = face2->frontarea != tmparea1;
  969. } //end for
  970. } //end for
  971. qprintf("\r%6d", ++i);
  972. } //end for
  973. qprintf("\n");
  974. Log_Write("%6d areas checked for shared face flipping\r\n", i);
  975. } //end of the function AAS_FlipSharedFaces
  976. //===========================================================================
  977. // creates an .AAS file with the given name
  978. // a MAP should be loaded before calling this
  979. //
  980. // Parameter: -
  981. // Returns: -
  982. // Changes Globals: -
  983. //===========================================================================
  984. void AAS_Create(char *aasfile)
  985. {
  986. entity_t *e;
  987. tree_t *tree;
  988. double start_time;
  989. //for a possible leak file
  990. strcpy(source, aasfile);
  991. StripExtension(source);
  992. //the time started
  993. start_time = I_FloatTime();
  994. //set the default number of threads (depends on number of processors)
  995. ThreadSetDefault();
  996. //set the global entity number to the world model
  997. entity_num = 0;
  998. //the world entity
  999. e = &entities[entity_num];
  1000. //process the whole world
  1001. tree = ProcessWorldBrushes(e->firstbrush, e->firstbrush + e->numbrushes);
  1002. //if the conversion is cancelled
  1003. if (cancelconversion)
  1004. {
  1005. Tree_Free(tree);
  1006. return;
  1007. } //end if
  1008. //display BSP tree creation time
  1009. Log_Print("BSP tree created in %5.0f seconds\n", I_FloatTime() - start_time);
  1010. //prune the bsp tree
  1011. Tree_PruneNodes(tree->headnode);
  1012. //if the conversion is cancelled
  1013. if (cancelconversion)
  1014. {
  1015. Tree_Free(tree);
  1016. return;
  1017. } //end if
  1018. //create the tree portals
  1019. MakeTreePortals(tree);
  1020. //if the conversion is cancelled
  1021. if (cancelconversion)
  1022. {
  1023. Tree_Free(tree);
  1024. return;
  1025. } //end if
  1026. //Marks all nodes that can be reached by entites
  1027. if (FloodEntities(tree))
  1028. {
  1029. //fill out nodes that can't be reached
  1030. FillOutside(tree->headnode);
  1031. } //end if
  1032. else
  1033. {
  1034. LeakFile(tree);
  1035. Error("**** leaked ****\n");
  1036. return;
  1037. } //end else
  1038. //create AAS from the BSP tree
  1039. //==========================================
  1040. //initialize tmp aas
  1041. AAS_InitTmpAAS();
  1042. //create the convex areas from the leaves
  1043. AAS_CreateAreas(tree->headnode);
  1044. //free the BSP tree because it isn't used anymore
  1045. if (freetree) Tree_Free(tree);
  1046. //try to merge area faces
  1047. AAS_MergeAreaFaces();
  1048. //do gravitational subdivision
  1049. AAS_GravitationalSubdivision();
  1050. //merge faces if possible
  1051. AAS_MergeAreaFaces();
  1052. AAS_RemoveAreaFaceColinearPoints();
  1053. //merge areas if possible
  1054. AAS_MergeAreas();
  1055. //NOTE: prune nodes directly after area merging
  1056. AAS_PruneNodes();
  1057. //flip shared faces so they are all facing to the same area
  1058. AAS_FlipSharedFaces();
  1059. AAS_RemoveAreaFaceColinearPoints();
  1060. //merge faces if possible
  1061. AAS_MergeAreaFaces();
  1062. //merge area faces in the same plane
  1063. AAS_MergeAreaPlaneFaces();
  1064. //do ladder subdivision
  1065. AAS_LadderSubdivision();
  1066. //FIXME: melting is buggy
  1067. AAS_MeltAreaFaceWindings();
  1068. //remove tiny faces
  1069. AAS_RemoveTinyFaces();
  1070. //create area settings
  1071. AAS_CreateAreaSettings();
  1072. //check if the winding plane is equal to the face plane
  1073. //AAS_CheckAreaWindingPlanes();
  1074. //
  1075. //AAS_CheckSharedFaces();
  1076. //==========================================
  1077. //if the conversion is cancelled
  1078. if (cancelconversion)
  1079. {
  1080. Tree_Free(tree);
  1081. AAS_FreeTmpAAS();
  1082. return;
  1083. } //end if
  1084. //store the created AAS stuff in the AAS file format and write the file
  1085. AAS_StoreFile(aasfile);
  1086. //free the temporary AAS memory
  1087. AAS_FreeTmpAAS();
  1088. //display creation time
  1089. Log_Print("\nAAS created in %5.0f seconds\n", I_FloatTime() - start_time);
  1090. } //end of the function AAS_Create