be_aas_file.c 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  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. /*****************************************************************************
  19. * name: be_aas_file.c
  20. *
  21. * desc: AAS file loading/writing
  22. *
  23. * $Archive: /MissionPack/code/botlib/be_aas_file.c $
  24. *
  25. *****************************************************************************/
  26. #include "../game/q_shared.h"
  27. #include "l_memory.h"
  28. #include "l_script.h"
  29. #include "l_precomp.h"
  30. #include "l_struct.h"
  31. #include "l_libvar.h"
  32. #include "l_utils.h"
  33. #include "aasfile.h"
  34. #include "../game/botlib.h"
  35. #include "../game/be_aas.h"
  36. #include "be_aas_funcs.h"
  37. #include "be_interface.h"
  38. #include "be_aas_def.h"
  39. //#define AASFILEDEBUG
  40. //===========================================================================
  41. //
  42. // Parameter: -
  43. // Returns: -
  44. // Changes Globals: -
  45. //===========================================================================
  46. void AAS_SwapAASData(void)
  47. {
  48. int i, j;
  49. //bounding boxes
  50. for (i = 0; i < aasworld.numbboxes; i++)
  51. {
  52. aasworld.bboxes[i].presencetype = LittleLong(aasworld.bboxes[i].presencetype);
  53. aasworld.bboxes[i].flags = LittleLong(aasworld.bboxes[i].flags);
  54. for (j = 0; j < 3; j++)
  55. {
  56. aasworld.bboxes[i].mins[j] = LittleLong(aasworld.bboxes[i].mins[j]);
  57. aasworld.bboxes[i].maxs[j] = LittleLong(aasworld.bboxes[i].maxs[j]);
  58. } //end for
  59. } //end for
  60. //vertexes
  61. for (i = 0; i < aasworld.numvertexes; i++)
  62. {
  63. for (j = 0; j < 3; j++)
  64. aasworld.vertexes[i][j] = LittleFloat(aasworld.vertexes[i][j]);
  65. } //end for
  66. //planes
  67. for (i = 0; i < aasworld.numplanes; i++)
  68. {
  69. for (j = 0; j < 3; j++)
  70. aasworld.planes[i].normal[j] = LittleFloat(aasworld.planes[i].normal[j]);
  71. aasworld.planes[i].dist = LittleFloat(aasworld.planes[i].dist);
  72. aasworld.planes[i].type = LittleLong(aasworld.planes[i].type);
  73. } //end for
  74. //edges
  75. for (i = 0; i < aasworld.numedges; i++)
  76. {
  77. aasworld.edges[i].v[0] = LittleLong(aasworld.edges[i].v[0]);
  78. aasworld.edges[i].v[1] = LittleLong(aasworld.edges[i].v[1]);
  79. } //end for
  80. //edgeindex
  81. for (i = 0; i < aasworld.edgeindexsize; i++)
  82. {
  83. aasworld.edgeindex[i] = LittleLong(aasworld.edgeindex[i]);
  84. } //end for
  85. //faces
  86. for (i = 0; i < aasworld.numfaces; i++)
  87. {
  88. aasworld.faces[i].planenum = LittleLong(aasworld.faces[i].planenum);
  89. aasworld.faces[i].faceflags = LittleLong(aasworld.faces[i].faceflags);
  90. aasworld.faces[i].numedges = LittleLong(aasworld.faces[i].numedges);
  91. aasworld.faces[i].firstedge = LittleLong(aasworld.faces[i].firstedge);
  92. aasworld.faces[i].frontarea = LittleLong(aasworld.faces[i].frontarea);
  93. aasworld.faces[i].backarea = LittleLong(aasworld.faces[i].backarea);
  94. } //end for
  95. //face index
  96. for (i = 0; i < aasworld.faceindexsize; i++)
  97. {
  98. aasworld.faceindex[i] = LittleLong(aasworld.faceindex[i]);
  99. } //end for
  100. //convex areas
  101. for (i = 0; i < aasworld.numareas; i++)
  102. {
  103. aasworld.areas[i].areanum = LittleLong(aasworld.areas[i].areanum);
  104. aasworld.areas[i].numfaces = LittleLong(aasworld.areas[i].numfaces);
  105. aasworld.areas[i].firstface = LittleLong(aasworld.areas[i].firstface);
  106. for (j = 0; j < 3; j++)
  107. {
  108. aasworld.areas[i].mins[j] = LittleFloat(aasworld.areas[i].mins[j]);
  109. aasworld.areas[i].maxs[j] = LittleFloat(aasworld.areas[i].maxs[j]);
  110. aasworld.areas[i].center[j] = LittleFloat(aasworld.areas[i].center[j]);
  111. } //end for
  112. } //end for
  113. //area settings
  114. for (i = 0; i < aasworld.numareasettings; i++)
  115. {
  116. aasworld.areasettings[i].contents = LittleLong(aasworld.areasettings[i].contents);
  117. aasworld.areasettings[i].areaflags = LittleLong(aasworld.areasettings[i].areaflags);
  118. aasworld.areasettings[i].presencetype = LittleLong(aasworld.areasettings[i].presencetype);
  119. aasworld.areasettings[i].cluster = LittleLong(aasworld.areasettings[i].cluster);
  120. aasworld.areasettings[i].clusterareanum = LittleLong(aasworld.areasettings[i].clusterareanum);
  121. aasworld.areasettings[i].numreachableareas = LittleLong(aasworld.areasettings[i].numreachableareas);
  122. aasworld.areasettings[i].firstreachablearea = LittleLong(aasworld.areasettings[i].firstreachablearea);
  123. } //end for
  124. //area reachability
  125. for (i = 0; i < aasworld.reachabilitysize; i++)
  126. {
  127. aasworld.reachability[i].areanum = LittleLong(aasworld.reachability[i].areanum);
  128. aasworld.reachability[i].facenum = LittleLong(aasworld.reachability[i].facenum);
  129. aasworld.reachability[i].edgenum = LittleLong(aasworld.reachability[i].edgenum);
  130. for (j = 0; j < 3; j++)
  131. {
  132. aasworld.reachability[i].start[j] = LittleFloat(aasworld.reachability[i].start[j]);
  133. aasworld.reachability[i].end[j] = LittleFloat(aasworld.reachability[i].end[j]);
  134. } //end for
  135. aasworld.reachability[i].traveltype = LittleLong(aasworld.reachability[i].traveltype);
  136. aasworld.reachability[i].traveltime = LittleShort(aasworld.reachability[i].traveltime);
  137. } //end for
  138. //nodes
  139. for (i = 0; i < aasworld.numnodes; i++)
  140. {
  141. aasworld.nodes[i].planenum = LittleLong(aasworld.nodes[i].planenum);
  142. aasworld.nodes[i].children[0] = LittleLong(aasworld.nodes[i].children[0]);
  143. aasworld.nodes[i].children[1] = LittleLong(aasworld.nodes[i].children[1]);
  144. } //end for
  145. //cluster portals
  146. for (i = 0; i < aasworld.numportals; i++)
  147. {
  148. aasworld.portals[i].areanum = LittleLong(aasworld.portals[i].areanum);
  149. aasworld.portals[i].frontcluster = LittleLong(aasworld.portals[i].frontcluster);
  150. aasworld.portals[i].backcluster = LittleLong(aasworld.portals[i].backcluster);
  151. aasworld.portals[i].clusterareanum[0] = LittleLong(aasworld.portals[i].clusterareanum[0]);
  152. aasworld.portals[i].clusterareanum[1] = LittleLong(aasworld.portals[i].clusterareanum[1]);
  153. } //end for
  154. //cluster portal index
  155. for (i = 0; i < aasworld.portalindexsize; i++)
  156. {
  157. aasworld.portalindex[i] = LittleLong(aasworld.portalindex[i]);
  158. } //end for
  159. //cluster
  160. for (i = 0; i < aasworld.numclusters; i++)
  161. {
  162. aasworld.clusters[i].numareas = LittleLong(aasworld.clusters[i].numareas);
  163. aasworld.clusters[i].numreachabilityareas = LittleLong(aasworld.clusters[i].numreachabilityareas);
  164. aasworld.clusters[i].numportals = LittleLong(aasworld.clusters[i].numportals);
  165. aasworld.clusters[i].firstportal = LittleLong(aasworld.clusters[i].firstportal);
  166. } //end for
  167. } //end of the function AAS_SwapAASData
  168. //===========================================================================
  169. // dump the current loaded aas file
  170. //
  171. // Parameter: -
  172. // Returns: -
  173. // Changes Globals: -
  174. //===========================================================================
  175. void AAS_DumpAASData(void)
  176. {
  177. aasworld.numbboxes = 0;
  178. if (aasworld.bboxes) FreeMemory(aasworld.bboxes);
  179. aasworld.bboxes = NULL;
  180. aasworld.numvertexes = 0;
  181. if (aasworld.vertexes) FreeMemory(aasworld.vertexes);
  182. aasworld.vertexes = NULL;
  183. aasworld.numplanes = 0;
  184. if (aasworld.planes) FreeMemory(aasworld.planes);
  185. aasworld.planes = NULL;
  186. aasworld.numedges = 0;
  187. if (aasworld.edges) FreeMemory(aasworld.edges);
  188. aasworld.edges = NULL;
  189. aasworld.edgeindexsize = 0;
  190. if (aasworld.edgeindex) FreeMemory(aasworld.edgeindex);
  191. aasworld.edgeindex = NULL;
  192. aasworld.numfaces = 0;
  193. if (aasworld.faces) FreeMemory(aasworld.faces);
  194. aasworld.faces = NULL;
  195. aasworld.faceindexsize = 0;
  196. if (aasworld.faceindex) FreeMemory(aasworld.faceindex);
  197. aasworld.faceindex = NULL;
  198. aasworld.numareas = 0;
  199. if (aasworld.areas) FreeMemory(aasworld.areas);
  200. aasworld.areas = NULL;
  201. aasworld.numareasettings = 0;
  202. if (aasworld.areasettings) FreeMemory(aasworld.areasettings);
  203. aasworld.areasettings = NULL;
  204. aasworld.reachabilitysize = 0;
  205. if (aasworld.reachability) FreeMemory(aasworld.reachability);
  206. aasworld.reachability = NULL;
  207. aasworld.numnodes = 0;
  208. if (aasworld.nodes) FreeMemory(aasworld.nodes);
  209. aasworld.nodes = NULL;
  210. aasworld.numportals = 0;
  211. if (aasworld.portals) FreeMemory(aasworld.portals);
  212. aasworld.portals = NULL;
  213. aasworld.numportals = 0;
  214. if (aasworld.portalindex) FreeMemory(aasworld.portalindex);
  215. aasworld.portalindex = NULL;
  216. aasworld.portalindexsize = 0;
  217. if (aasworld.clusters) FreeMemory(aasworld.clusters);
  218. aasworld.clusters = NULL;
  219. aasworld.numclusters = 0;
  220. //
  221. aasworld.loaded = qfalse;
  222. aasworld.initialized = qfalse;
  223. aasworld.savefile = qfalse;
  224. } //end of the function AAS_DumpAASData
  225. //===========================================================================
  226. //
  227. // Parameter: -
  228. // Returns: -
  229. // Changes Globals: -
  230. //===========================================================================
  231. #ifdef AASFILEDEBUG
  232. void AAS_FileInfo(void)
  233. {
  234. int i, n, optimized;
  235. botimport.Print(PRT_MESSAGE, "version = %d\n", AASVERSION);
  236. botimport.Print(PRT_MESSAGE, "numvertexes = %d\n", aasworld.numvertexes);
  237. botimport.Print(PRT_MESSAGE, "numplanes = %d\n", aasworld.numplanes);
  238. botimport.Print(PRT_MESSAGE, "numedges = %d\n", aasworld.numedges);
  239. botimport.Print(PRT_MESSAGE, "edgeindexsize = %d\n", aasworld.edgeindexsize);
  240. botimport.Print(PRT_MESSAGE, "numfaces = %d\n", aasworld.numfaces);
  241. botimport.Print(PRT_MESSAGE, "faceindexsize = %d\n", aasworld.faceindexsize);
  242. botimport.Print(PRT_MESSAGE, "numareas = %d\n", aasworld.numareas);
  243. botimport.Print(PRT_MESSAGE, "numareasettings = %d\n", aasworld.numareasettings);
  244. botimport.Print(PRT_MESSAGE, "reachabilitysize = %d\n", aasworld.reachabilitysize);
  245. botimport.Print(PRT_MESSAGE, "numnodes = %d\n", aasworld.numnodes);
  246. botimport.Print(PRT_MESSAGE, "numportals = %d\n", aasworld.numportals);
  247. botimport.Print(PRT_MESSAGE, "portalindexsize = %d\n", aasworld.portalindexsize);
  248. botimport.Print(PRT_MESSAGE, "numclusters = %d\n", aasworld.numclusters);
  249. //
  250. for (n = 0, i = 0; i < aasworld.numareasettings; i++)
  251. {
  252. if (aasworld.areasettings[i].areaflags & AREA_GROUNDED) n++;
  253. } //end for
  254. botimport.Print(PRT_MESSAGE, "num grounded areas = %d\n", n);
  255. //
  256. botimport.Print(PRT_MESSAGE, "planes size %d bytes\n", aasworld.numplanes * sizeof(aas_plane_t));
  257. botimport.Print(PRT_MESSAGE, "areas size %d bytes\n", aasworld.numareas * sizeof(aas_area_t));
  258. botimport.Print(PRT_MESSAGE, "areasettings size %d bytes\n", aasworld.numareasettings * sizeof(aas_areasettings_t));
  259. botimport.Print(PRT_MESSAGE, "nodes size %d bytes\n", aasworld.numnodes * sizeof(aas_node_t));
  260. botimport.Print(PRT_MESSAGE, "reachability size %d bytes\n", aasworld.reachabilitysize * sizeof(aas_reachability_t));
  261. botimport.Print(PRT_MESSAGE, "portals size %d bytes\n", aasworld.numportals * sizeof(aas_portal_t));
  262. botimport.Print(PRT_MESSAGE, "clusters size %d bytes\n", aasworld.numclusters * sizeof(aas_cluster_t));
  263. optimized = aasworld.numplanes * sizeof(aas_plane_t) +
  264. aasworld.numareas * sizeof(aas_area_t) +
  265. aasworld.numareasettings * sizeof(aas_areasettings_t) +
  266. aasworld.numnodes * sizeof(aas_node_t) +
  267. aasworld.reachabilitysize * sizeof(aas_reachability_t) +
  268. aasworld.numportals * sizeof(aas_portal_t) +
  269. aasworld.numclusters * sizeof(aas_cluster_t);
  270. botimport.Print(PRT_MESSAGE, "optimzed size %d KB\n", optimized >> 10);
  271. } //end of the function AAS_FileInfo
  272. #endif //AASFILEDEBUG
  273. //===========================================================================
  274. // allocate memory and read a lump of a AAS file
  275. //
  276. // Parameter: -
  277. // Returns: -
  278. // Changes Globals: -
  279. //===========================================================================
  280. char *AAS_LoadAASLump(fileHandle_t fp, int offset, int length, int *lastoffset, int size)
  281. {
  282. char *buf;
  283. //
  284. if (!length)
  285. {
  286. //just alloc a dummy
  287. return (char *) GetClearedHunkMemory(size+1);
  288. } //end if
  289. //seek to the data
  290. if (offset != *lastoffset)
  291. {
  292. botimport.Print(PRT_WARNING, "AAS file not sequentially read\n");
  293. if (botimport.FS_Seek(fp, offset, FS_SEEK_SET))
  294. {
  295. AAS_Error("can't seek to aas lump\n");
  296. AAS_DumpAASData();
  297. botimport.FS_FCloseFile(fp);
  298. return 0;
  299. } //end if
  300. } //end if
  301. //allocate memory
  302. buf = (char *) GetClearedHunkMemory(length+1);
  303. //read the data
  304. if (length)
  305. {
  306. botimport.FS_Read(buf, length, fp );
  307. *lastoffset += length;
  308. } //end if
  309. return buf;
  310. } //end of the function AAS_LoadAASLump
  311. //===========================================================================
  312. //
  313. // Parameter: -
  314. // Returns: -
  315. // Changes Globals: -
  316. //===========================================================================
  317. void AAS_DData(unsigned char *data, int size)
  318. {
  319. int i;
  320. for (i = 0; i < size; i++)
  321. {
  322. data[i] ^= (unsigned char) i * 119;
  323. } //end for
  324. } //end of the function AAS_DData
  325. //===========================================================================
  326. // load an aas file
  327. //
  328. // Parameter: -
  329. // Returns: -
  330. // Changes Globals: -
  331. //===========================================================================
  332. int AAS_LoadAASFile(char *filename)
  333. {
  334. fileHandle_t fp;
  335. aas_header_t header;
  336. int offset, length, lastoffset;
  337. botimport.Print(PRT_MESSAGE, "trying to load %s\n", filename);
  338. //dump current loaded aas file
  339. AAS_DumpAASData();
  340. //open the file
  341. botimport.FS_FOpenFile( filename, &fp, FS_READ );
  342. if (!fp)
  343. {
  344. AAS_Error("can't open %s\n", filename);
  345. return BLERR_CANNOTOPENAASFILE;
  346. } //end if
  347. //read the header
  348. botimport.FS_Read(&header, sizeof(aas_header_t), fp );
  349. lastoffset = sizeof(aas_header_t);
  350. //check header identification
  351. header.ident = LittleLong(header.ident);
  352. if (header.ident != AASID)
  353. {
  354. AAS_Error("%s is not an AAS file\n", filename);
  355. botimport.FS_FCloseFile(fp);
  356. return BLERR_WRONGAASFILEID;
  357. } //end if
  358. //check the version
  359. header.version = LittleLong(header.version);
  360. //
  361. if (header.version != AASVERSION_OLD && header.version != AASVERSION)
  362. {
  363. AAS_Error("aas file %s is version %i, not %i\n", filename, header.version, AASVERSION);
  364. botimport.FS_FCloseFile(fp);
  365. return BLERR_WRONGAASFILEVERSION;
  366. } //end if
  367. //
  368. if (header.version == AASVERSION)
  369. {
  370. AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
  371. } //end if
  372. //
  373. aasworld.bspchecksum = atoi(LibVarGetString( "sv_mapChecksum"));
  374. if (LittleLong(header.bspchecksum) != aasworld.bspchecksum)
  375. {
  376. AAS_Error("aas file %s is out of date\n", filename);
  377. botimport.FS_FCloseFile(fp);
  378. return BLERR_WRONGAASFILEVERSION;
  379. } //end if
  380. //load the lumps:
  381. //bounding boxes
  382. offset = LittleLong(header.lumps[AASLUMP_BBOXES].fileofs);
  383. length = LittleLong(header.lumps[AASLUMP_BBOXES].filelen);
  384. aasworld.bboxes = (aas_bbox_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_bbox_t));
  385. aasworld.numbboxes = length / sizeof(aas_bbox_t);
  386. if (aasworld.numbboxes && !aasworld.bboxes) return BLERR_CANNOTREADAASLUMP;
  387. //vertexes
  388. offset = LittleLong(header.lumps[AASLUMP_VERTEXES].fileofs);
  389. length = LittleLong(header.lumps[AASLUMP_VERTEXES].filelen);
  390. aasworld.vertexes = (aas_vertex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_vertex_t));
  391. aasworld.numvertexes = length / sizeof(aas_vertex_t);
  392. if (aasworld.numvertexes && !aasworld.vertexes) return BLERR_CANNOTREADAASLUMP;
  393. //planes
  394. offset = LittleLong(header.lumps[AASLUMP_PLANES].fileofs);
  395. length = LittleLong(header.lumps[AASLUMP_PLANES].filelen);
  396. aasworld.planes = (aas_plane_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_plane_t));
  397. aasworld.numplanes = length / sizeof(aas_plane_t);
  398. if (aasworld.numplanes && !aasworld.planes) return BLERR_CANNOTREADAASLUMP;
  399. //edges
  400. offset = LittleLong(header.lumps[AASLUMP_EDGES].fileofs);
  401. length = LittleLong(header.lumps[AASLUMP_EDGES].filelen);
  402. aasworld.edges = (aas_edge_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edge_t));
  403. aasworld.numedges = length / sizeof(aas_edge_t);
  404. if (aasworld.numedges && !aasworld.edges) return BLERR_CANNOTREADAASLUMP;
  405. //edgeindex
  406. offset = LittleLong(header.lumps[AASLUMP_EDGEINDEX].fileofs);
  407. length = LittleLong(header.lumps[AASLUMP_EDGEINDEX].filelen);
  408. aasworld.edgeindex = (aas_edgeindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_edgeindex_t));
  409. aasworld.edgeindexsize = length / sizeof(aas_edgeindex_t);
  410. if (aasworld.edgeindexsize && !aasworld.edgeindex) return BLERR_CANNOTREADAASLUMP;
  411. //faces
  412. offset = LittleLong(header.lumps[AASLUMP_FACES].fileofs);
  413. length = LittleLong(header.lumps[AASLUMP_FACES].filelen);
  414. aasworld.faces = (aas_face_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_face_t));
  415. aasworld.numfaces = length / sizeof(aas_face_t);
  416. if (aasworld.numfaces && !aasworld.faces) return BLERR_CANNOTREADAASLUMP;
  417. //faceindex
  418. offset = LittleLong(header.lumps[AASLUMP_FACEINDEX].fileofs);
  419. length = LittleLong(header.lumps[AASLUMP_FACEINDEX].filelen);
  420. aasworld.faceindex = (aas_faceindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_faceindex_t));
  421. aasworld.faceindexsize = length / sizeof(aas_faceindex_t);
  422. if (aasworld.faceindexsize && !aasworld.faceindex) return BLERR_CANNOTREADAASLUMP;
  423. //convex areas
  424. offset = LittleLong(header.lumps[AASLUMP_AREAS].fileofs);
  425. length = LittleLong(header.lumps[AASLUMP_AREAS].filelen);
  426. aasworld.areas = (aas_area_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_area_t));
  427. aasworld.numareas = length / sizeof(aas_area_t);
  428. if (aasworld.numareas && !aasworld.areas) return BLERR_CANNOTREADAASLUMP;
  429. //area settings
  430. offset = LittleLong(header.lumps[AASLUMP_AREASETTINGS].fileofs);
  431. length = LittleLong(header.lumps[AASLUMP_AREASETTINGS].filelen);
  432. aasworld.areasettings = (aas_areasettings_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_areasettings_t));
  433. aasworld.numareasettings = length / sizeof(aas_areasettings_t);
  434. if (aasworld.numareasettings && !aasworld.areasettings) return BLERR_CANNOTREADAASLUMP;
  435. //reachability list
  436. offset = LittleLong(header.lumps[AASLUMP_REACHABILITY].fileofs);
  437. length = LittleLong(header.lumps[AASLUMP_REACHABILITY].filelen);
  438. aasworld.reachability = (aas_reachability_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_reachability_t));
  439. aasworld.reachabilitysize = length / sizeof(aas_reachability_t);
  440. if (aasworld.reachabilitysize && !aasworld.reachability) return BLERR_CANNOTREADAASLUMP;
  441. //nodes
  442. offset = LittleLong(header.lumps[AASLUMP_NODES].fileofs);
  443. length = LittleLong(header.lumps[AASLUMP_NODES].filelen);
  444. aasworld.nodes = (aas_node_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_node_t));
  445. aasworld.numnodes = length / sizeof(aas_node_t);
  446. if (aasworld.numnodes && !aasworld.nodes) return BLERR_CANNOTREADAASLUMP;
  447. //cluster portals
  448. offset = LittleLong(header.lumps[AASLUMP_PORTALS].fileofs);
  449. length = LittleLong(header.lumps[AASLUMP_PORTALS].filelen);
  450. aasworld.portals = (aas_portal_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portal_t));
  451. aasworld.numportals = length / sizeof(aas_portal_t);
  452. if (aasworld.numportals && !aasworld.portals) return BLERR_CANNOTREADAASLUMP;
  453. //cluster portal index
  454. offset = LittleLong(header.lumps[AASLUMP_PORTALINDEX].fileofs);
  455. length = LittleLong(header.lumps[AASLUMP_PORTALINDEX].filelen);
  456. aasworld.portalindex = (aas_portalindex_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_portalindex_t));
  457. aasworld.portalindexsize = length / sizeof(aas_portalindex_t);
  458. if (aasworld.portalindexsize && !aasworld.portalindex) return BLERR_CANNOTREADAASLUMP;
  459. //clusters
  460. offset = LittleLong(header.lumps[AASLUMP_CLUSTERS].fileofs);
  461. length = LittleLong(header.lumps[AASLUMP_CLUSTERS].filelen);
  462. aasworld.clusters = (aas_cluster_t *) AAS_LoadAASLump(fp, offset, length, &lastoffset, sizeof(aas_cluster_t));
  463. aasworld.numclusters = length / sizeof(aas_cluster_t);
  464. if (aasworld.numclusters && !aasworld.clusters) return BLERR_CANNOTREADAASLUMP;
  465. //swap everything
  466. AAS_SwapAASData();
  467. //aas file is loaded
  468. aasworld.loaded = qtrue;
  469. //close the file
  470. botimport.FS_FCloseFile(fp);
  471. //
  472. #ifdef AASFILEDEBUG
  473. AAS_FileInfo();
  474. #endif //AASFILEDEBUG
  475. //
  476. return BLERR_NOERROR;
  477. } //end of the function AAS_LoadAASFile
  478. //===========================================================================
  479. //
  480. // Parameter: -
  481. // Returns: -
  482. // Changes Globals: -
  483. //===========================================================================
  484. static int AAS_WriteAASLump_offset;
  485. int AAS_WriteAASLump(fileHandle_t fp, aas_header_t *h, int lumpnum, void *data, int length)
  486. {
  487. aas_lump_t *lump;
  488. lump = &h->lumps[lumpnum];
  489. lump->fileofs = LittleLong(AAS_WriteAASLump_offset); //LittleLong(ftell(fp));
  490. lump->filelen = LittleLong(length);
  491. if (length > 0)
  492. {
  493. botimport.FS_Write(data, length, fp );
  494. } //end if
  495. AAS_WriteAASLump_offset += length;
  496. return qtrue;
  497. } //end of the function AAS_WriteAASLump
  498. //===========================================================================
  499. // aas data is useless after writing to file because it is byte swapped
  500. //
  501. // Parameter: -
  502. // Returns: -
  503. // Changes Globals: -
  504. //===========================================================================
  505. qboolean AAS_WriteAASFile(char *filename)
  506. {
  507. aas_header_t header;
  508. fileHandle_t fp;
  509. botimport.Print(PRT_MESSAGE, "writing %s\n", filename);
  510. //swap the aas data
  511. AAS_SwapAASData();
  512. //initialize the file header
  513. Com_Memset(&header, 0, sizeof(aas_header_t));
  514. header.ident = LittleLong(AASID);
  515. header.version = LittleLong(AASVERSION);
  516. header.bspchecksum = LittleLong(aasworld.bspchecksum);
  517. //open a new file
  518. botimport.FS_FOpenFile( filename, &fp, FS_WRITE );
  519. if (!fp)
  520. {
  521. botimport.Print(PRT_ERROR, "error opening %s\n", filename);
  522. return qfalse;
  523. } //end if
  524. //write the header
  525. botimport.FS_Write(&header, sizeof(aas_header_t), fp);
  526. AAS_WriteAASLump_offset = sizeof(aas_header_t);
  527. //add the data lumps to the file
  528. if (!AAS_WriteAASLump(fp, &header, AASLUMP_BBOXES, aasworld.bboxes,
  529. aasworld.numbboxes * sizeof(aas_bbox_t))) return qfalse;
  530. if (!AAS_WriteAASLump(fp, &header, AASLUMP_VERTEXES, aasworld.vertexes,
  531. aasworld.numvertexes * sizeof(aas_vertex_t))) return qfalse;
  532. if (!AAS_WriteAASLump(fp, &header, AASLUMP_PLANES, aasworld.planes,
  533. aasworld.numplanes * sizeof(aas_plane_t))) return qfalse;
  534. if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGES, aasworld.edges,
  535. aasworld.numedges * sizeof(aas_edge_t))) return qfalse;
  536. if (!AAS_WriteAASLump(fp, &header, AASLUMP_EDGEINDEX, aasworld.edgeindex,
  537. aasworld.edgeindexsize * sizeof(aas_edgeindex_t))) return qfalse;
  538. if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACES, aasworld.faces,
  539. aasworld.numfaces * sizeof(aas_face_t))) return qfalse;
  540. if (!AAS_WriteAASLump(fp, &header, AASLUMP_FACEINDEX, aasworld.faceindex,
  541. aasworld.faceindexsize * sizeof(aas_faceindex_t))) return qfalse;
  542. if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREAS, aasworld.areas,
  543. aasworld.numareas * sizeof(aas_area_t))) return qfalse;
  544. if (!AAS_WriteAASLump(fp, &header, AASLUMP_AREASETTINGS, aasworld.areasettings,
  545. aasworld.numareasettings * sizeof(aas_areasettings_t))) return qfalse;
  546. if (!AAS_WriteAASLump(fp, &header, AASLUMP_REACHABILITY, aasworld.reachability,
  547. aasworld.reachabilitysize * sizeof(aas_reachability_t))) return qfalse;
  548. if (!AAS_WriteAASLump(fp, &header, AASLUMP_NODES, aasworld.nodes,
  549. aasworld.numnodes * sizeof(aas_node_t))) return qfalse;
  550. if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALS, aasworld.portals,
  551. aasworld.numportals * sizeof(aas_portal_t))) return qfalse;
  552. if (!AAS_WriteAASLump(fp, &header, AASLUMP_PORTALINDEX, aasworld.portalindex,
  553. aasworld.portalindexsize * sizeof(aas_portalindex_t))) return qfalse;
  554. if (!AAS_WriteAASLump(fp, &header, AASLUMP_CLUSTERS, aasworld.clusters,
  555. aasworld.numclusters * sizeof(aas_cluster_t))) return qfalse;
  556. //rewrite the header with the added lumps
  557. botimport.FS_Seek(fp, 0, FS_SEEK_SET);
  558. AAS_DData((unsigned char *) &header + 8, sizeof(aas_header_t) - 8);
  559. botimport.FS_Write(&header, sizeof(aas_header_t), fp);
  560. //close the file
  561. botimport.FS_FCloseFile(fp);
  562. return qtrue;
  563. } //end of the function AAS_WriteAASFile