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