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