bsp.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2001 Id Software, Inc.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "common.h"
00027 #include "tracing.h"
00028 #include "routing.h"
00029 #include "../shared/parse.h"
00030 
00032 static cBspSurface_t nullSurface;
00033 
00034 /*
00035 ===============================================================================
00036 MAP LOADING
00037 ===============================================================================
00038 */
00039 
00048 static void CMod_LoadSubmodels (mapTile_t *tile, const byte *base, const lump_t * l, const vec3_t shift)
00049 {
00050     const dBspModel_t *in;
00051     cBspModel_t *out;
00052     int i, j, count;
00053 
00054     if (!l)
00055         Com_Error(ERR_DROP, "CMod_LoadSubmodels: No lump given");
00056 
00057     in = (const dBspModel_t *) (base + l->fileofs);
00058     if (l->filelen % sizeof(*in))
00059         Com_Error(ERR_DROP, "CMod_LoadSubmodels: funny lump size (%i => "UFO_SIZE_T")", l->filelen, sizeof(*in));
00060     count = l->filelen / sizeof(*in);
00061     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...submodels: %i\n", count);
00062 
00063     if (count < 1)
00064         Com_Error(ERR_DROP, "Map with no models");
00065     if (count > MAX_MAP_MODELS)
00066         Com_Error(ERR_DROP, "Map has too many models: %i", count);
00067 
00068     out = (cBspModel_t *)Mem_PoolAlloc((count + 6) * sizeof(*out), com_cmodelSysPool, 0);
00069     tile->models = out;
00070     tile->nummodels = count;
00071 
00072     for (i = 0; i < count; i++, in++, out++) {
00073         out = &tile->models[i];
00074 
00075         /* Record the shift in case we need to undo it. */
00076         VectorCopy(shift, out->shift);
00077         /* spread the mins / maxs by a pixel */
00078         for (j = 0; j < 3; j++) {
00079             out->mins[j] = LittleFloat(in->mins[j]) - 1 + shift[j];
00080             out->maxs[j] = LittleFloat(in->maxs[j]) + 1 + shift[j];
00081         }
00082         out->headnode = LittleLong(in->headnode);
00083         out->tile = tile->idx; /* backlink to the loaded map tile */
00084     }
00085 }
00086 
00087 
00092 static void CMod_LoadSurfaces (mapTile_t *tile, const byte *base, const lump_t * l)
00093 {
00094     const dBspTexinfo_t *in;
00095     cBspSurface_t *out;
00096     int i, count;
00097 
00098     if (!l)
00099         Com_Error(ERR_DROP, "CMod_LoadSurfaces: No lump given");
00100 
00101     in = (const dBspTexinfo_t *) (base + l->fileofs);
00102     if (l->filelen % sizeof(*in))
00103         Com_Error(ERR_DROP, "CMod_LoadSurfaces: funny lump size: %i", l->filelen);
00104     count = l->filelen / sizeof(*in);
00105     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...surfaces: %i\n", count);
00106 
00107     if (count < 1)
00108         Com_Error(ERR_DROP, "Map with no surfaces");
00109     if (count > MAX_MAP_TEXINFO)
00110         Com_Error(ERR_DROP, "Map has too many surfaces");
00111 
00112     out = (cBspSurface_t *)Mem_PoolAlloc(count * sizeof(*out), com_cmodelSysPool, 0);
00113 
00114     tile->surfaces = out;
00115     tile->numtexinfo = count;
00116 
00117     for (i = 0; i < count; i++, in++, out++) {
00118         Q_strncpyz(out->name, in->texture, sizeof(out->name));
00119         out->surfaceFlags = LittleLong(in->surfaceFlags);
00120         out->value = LittleLong(in->value);
00121     }
00122 }
00123 
00124 
00131 static void CMod_LoadNodes (mapTile_t *tile, const byte *base, const lump_t * l, const vec3_t shift)
00132 {
00133     const dBspNode_t *in;
00134     int child;
00135     cBspNode_t *out;
00136     int i, j, count;
00137 
00138     if (!l)
00139         Com_Error(ERR_DROP, "CMod_LoadNodes: No lump given");
00140 
00141     in = (const dBspNode_t *) (base + l->fileofs);
00142     if (l->filelen % sizeof(*in))
00143         Com_Error(ERR_DROP, "CMod_LoadNodes: funny lump size: %i", l->filelen);
00144     count = l->filelen / sizeof(*in);
00145     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...nodes: %i\n", count);
00146 
00147     if (count < 1)
00148         Com_Error(ERR_DROP, "Map has no nodes");
00149     if (count > MAX_MAP_NODES)
00150         Com_Error(ERR_DROP, "Map has too many nodes");
00151 
00152     /* add some for the box */
00153     out = (cBspNode_t *)Mem_PoolAlloc((count + 6) * sizeof(*out), com_cmodelSysPool, 0);
00154 
00155     tile->numnodes = count;
00156     tile->nodes = out;
00157 
00158     for (i = 0; i < count; i++, out++, in++) {
00159         if (LittleLong(in->planenum) == PLANENUM_LEAF)
00160             out->plane = NULL;
00161         else
00162             out->plane = tile->planes + LittleLong(in->planenum);
00163 
00164         /* in case this is a map assemble */
00165         for (j = 0; j < 3; j++) {
00166             out->mins[j] = LittleShort(in->mins[j]) + shift[j];
00167             out->maxs[j] = LittleShort(in->maxs[j]) + shift[j];
00168         }
00169 
00170         for (j = 0; j < 2; j++) {
00171             child = LittleLong(in->children[j]);
00172             out->children[j] = child;
00173         }
00174     }
00175 }
00176 
00181 static void CMod_LoadBrushes (mapTile_t *tile, const byte *base, const lump_t * l)
00182 {
00183     const dBspBrush_t *in;
00184     cBspBrush_t *out;
00185     int i, count;
00186 
00187     if (!l)
00188         Com_Error(ERR_DROP, "CMod_LoadBrushes: No lump given");
00189 
00190     in = (const dBspBrush_t *) (base + l->fileofs);
00191     if (l->filelen % sizeof(*in))
00192         Com_Error(ERR_DROP, "CMod_LoadBrushes: funny lump size: %i", l->filelen);
00193     count = l->filelen / sizeof(*in);
00194     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...brushes: %i\n", count);
00195 
00196     if (count > MAX_MAP_BRUSHES)
00197         Com_Error(ERR_DROP, "Map has too many brushes");
00198 
00199     /* add some for the box */
00200     out = (cBspBrush_t *)Mem_PoolAlloc((count + 1) * sizeof(*out), com_cmodelSysPool, 0);
00201 
00202     tile->numbrushes = count;
00203     tile->brushes = out;
00204 
00205     for (i = 0; i < count; i++, out++, in++) {
00206         out->firstbrushside = LittleLong(in->firstbrushside);
00207         out->numsides = LittleLong(in->numsides);
00208         out->contentFlags = LittleLong(in->contentFlags);
00209     }
00210 }
00211 
00216 static void CMod_LoadLeafs (mapTile_t *tile, const byte *base, const lump_t * l)
00217 {
00218     int i;
00219     cBspLeaf_t *out;
00220     const dBspLeaf_t *in;
00221     int count;
00222 
00223     if (!l)
00224         Com_Error(ERR_DROP, "CMod_LoadLeafs: No lump given");
00225 
00226     in = (const dBspLeaf_t *) (base + l->fileofs);
00227     if (l->filelen % sizeof(*in))
00228         Com_Error(ERR_DROP, "CMod_LoadLeafs: funny lump size: %i", l->filelen);
00229     count = l->filelen / sizeof(*in);
00230     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...leafs: %i\n", count);
00231 
00232     if (count < 1)
00233         Com_Error(ERR_DROP, "Map with no leafs");
00234     /* need to save space for box planes */
00235     if (count > MAX_MAP_LEAFS)
00236         Com_Error(ERR_DROP, "Map has too many leafs");
00237 
00238     /* add some for the box */
00239     out = (cBspLeaf_t *)Mem_PoolAlloc((count + 1) * sizeof(*out), com_cmodelSysPool, 0);
00240 
00241     tile->numleafs = count;
00242     tile->leafs = out;
00243 
00244     for (i = 0; i < count; i++, in++, out++) {
00245         out->contentFlags = LittleLong(in->contentFlags);
00246         out->firstleafbrush = LittleShort(in->firstleafbrush);
00247         out->numleafbrushes = LittleShort(in->numleafbrushes);
00248     }
00249 
00250     if (tile->leafs[0].contentFlags != CONTENTS_SOLID)
00251         Com_Error(ERR_DROP, "Map leaf 0 is not CONTENTS_SOLID");
00252     tile->emptyleaf = -1;
00253     for (i = 1; i < tile->numleafs; i++) {
00254         if (!tile->leafs[i].contentFlags) {
00255             tile->emptyleaf = i;
00256             break;
00257         }
00258     }
00259     if (tile->emptyleaf == -1)
00260         Com_Error(ERR_DROP, "Map does not have an empty leaf");
00261 }
00262 
00269 static void CMod_LoadPlanes (mapTile_t *tile, const byte *base, const lump_t * l, const vec3_t shift)
00270 {
00271     int i, j;
00272     cBspPlane_t *out;
00273     const dBspPlane_t *in;
00274     int count;
00275 
00276     if (!l)
00277         Com_Error(ERR_DROP, "CMod_LoadPlanes: No lump given");
00278 
00279     in = (const dBspPlane_t *) (base + l->fileofs);
00280     if (l->filelen % sizeof(*in))
00281         Com_Error(ERR_DROP, "CMod_LoadPlanes: funny lump size: %i", l->filelen);
00282     count = l->filelen / sizeof(*in);
00283     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...planes: %i\n", count);
00284 
00285     if (count < 1)
00286         Com_Error(ERR_DROP, "Map with no planes");
00287     /* need to save space for box planes */
00288     if (count > MAX_MAP_PLANES)
00289         Com_Error(ERR_DROP, "Map has too many planes");
00290 
00291     /* add some for the box */
00292     out = (cBspPlane_t *)Mem_PoolAlloc((count + 12) * sizeof(*out), com_cmodelSysPool, 0);
00293 
00294     tile->numplanes = count;
00295     tile->planes = out;
00296 
00297     for (i = 0; i < count; i++, in++, out++) {
00298         out->dist = LittleFloat(in->dist);
00299         out->type = LittleLong(in->type);
00300 
00301         /* load normals and shift (map assembly) */
00302         for (j = 0; j < 3; j++) {
00303             out->normal[j] = LittleFloat(in->normal[j]);
00304             out->dist += out->normal[j] * shift[j];
00305         }
00306     }
00307 }
00308 
00313 static void CMod_LoadLeafBrushes (mapTile_t *tile, const byte *base, const lump_t * l)
00314 {
00315     int i;
00316     unsigned short *out;
00317     const unsigned short *in;
00318     int count;
00319 
00320     if (!l)
00321         Com_Error(ERR_DROP, "CMod_LoadLeafBrushes: No lump given");
00322 
00323     in = (const unsigned short *) (base + l->fileofs);
00324     if (l->filelen % sizeof(unsigned short))
00325         Com_Error(ERR_DROP, "CMod_LoadLeafBrushes: funny lump size: %i", l->filelen);
00326     count = l->filelen / sizeof(unsigned short);
00327     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...leafbrushes: %i\n", count);
00328 
00329     /* add some for the box */
00330     out = (unsigned short *)Mem_PoolAlloc((count + 1) * sizeof(*out), com_cmodelSysPool, 0);
00331 
00332     if (count < 1)
00333         Com_Error(ERR_DROP, "Map with no planes");
00334     /* need to save space for box planes */
00335     if (count >= MAX_MAP_LEAFBRUSHES)
00336         Com_Error(ERR_DROP, "Map has too many leafbrushes");
00337 
00338     tile->numleafbrushes = count;
00339     tile->leafbrushes = out;
00340 
00341     for (i = 0; i < count; i++, in++, out++)
00342         *out = LittleShort(*in);
00343 }
00344 
00349 static void CMod_LoadBrushSides (mapTile_t *tile, const byte *base, const lump_t * l)
00350 {
00351     int i;
00352     cBspBrushSide_t *out;
00353     const dBspBrushSide_t *in;
00354     int count;
00355 
00356     if (!l)
00357         Com_Error(ERR_DROP, "CMod_LoadBrushSides: No lump given");
00358 
00359     in = (const dBspBrushSide_t *) (base + l->fileofs);
00360     if (l->filelen % sizeof(dBspBrushSide_t))
00361         Com_Error(ERR_DROP, "CMod_LoadBrushSides: funny lump size: %i", l->filelen);
00362     count = l->filelen / sizeof(dBspBrushSide_t);
00363     Com_DPrintf(DEBUG_ENGINE, COLORED_GREEN "...brushsides: %i\n", count);
00364 
00365     /* need to save space for box planes */
00366     if (count > MAX_MAP_BRUSHSIDES)
00367         Com_Error(ERR_DROP, "Map has too many brushsides");
00368 
00369     /* add some for the box */
00370     out = (cBspBrushSide_t *)Mem_PoolAlloc((count + 6) * sizeof(*out), com_cmodelSysPool, 0);
00371 
00372     tile->numbrushsides = count;
00373     tile->brushsides = out;
00374 
00375     for (i = 0; i < count; i++, in++, out++) {
00376         const int num = LittleShort(in->planenum);
00377         const int j = LittleShort(in->texinfo);
00378         if (j >= tile->numtexinfo)
00379             Com_Error(ERR_DROP, "Bad brushside texinfo");
00380         out->plane = &tile->planes[num];
00381         out->surface = &tile->surfaces[j];
00382     }
00383 }
00384 
00391 static int CMod_DeCompressRouting (const byte ** source, byte * dataStart)
00392 {
00393     int i, c;
00394     byte *data_p;
00395     const byte *src;
00396 
00397     data_p = dataStart;
00398     src = *source;
00399 
00400     while (*src) {
00401         if (*src & 0x80) {
00402             /* repetitions */
00403             c = *src++ & ~0x80;
00404             /* Remember that the total bytes that are the same is c + 2 */
00405             for (i = 0; i < c + 2; i++)
00406                 *data_p++ = *src;
00407             src++;
00408         } else {
00409             /* identities */
00410             c = *src++;
00411             for (i = 0; i < c; i++)
00412                 *data_p++ = *src++;
00413         }
00414     }
00415 
00416     src++;
00417     *source = src;
00418 
00419     return data_p - dataStart;
00420 }
00421 
00422 /*
00423 ===============================================================================
00424 TRACING NODES
00425 ===============================================================================
00426 */
00427 
00434 static void CM_MakeTracingNodes (mapTile_t *tile)
00435 {
00436     int i;
00437     tnode_t *tnode;
00438 
00439     tnode = tile->tnodes = (tnode_t *)Mem_PoolAlloc((tile->numnodes + 6) * sizeof(*tnode), com_cmodelSysPool, 0);
00440 
00441     tile->numtheads = 0;
00442     tile->numcheads = 0;
00443 
00444     for (i = 0; i < tile->nummodels; i++) {
00445         if (tile->models[i].headnode == LEAFNODE || tile->models[i].headnode >= tile->numnodes + 6)
00446             continue;
00447 
00448         tile->thead[tile->numtheads] = tnode - tile->tnodes;
00449         tile->theadlevel[tile->numtheads] = i;
00450         tile->numtheads++;
00451         assert(tile->numtheads < LEVEL_MAX);
00452 
00453         /* If this level (i) is the last visible level or earlier, then trace it.
00454          * Otherwise don't; we have separate checks for entities. */
00455         if (i < NUM_REGULAR_MODELS)
00456             TR_BuildTracingNode_r(tile, &tnode, tile->models[i].headnode, i);
00457     }
00458 }
00459 
00469 static void CMod_LoadRouting (mapTile_t *tile, mapData_t *mapData, const byte *base, const char *name, const lump_t * l, int sX, int sY, int sZ)
00470 {
00472     static routing_t tempMap[ACTOR_MAX_SIZE];
00473     const byte *source;
00474     int length;
00475     int x, y, z, size, dir;
00476     int minX, minY, minZ;
00477     int maxX, maxY, maxZ;
00478     unsigned int i;
00479     double start, end;
00480     const int targetLength = sizeof(tile->wpMins) + sizeof(tile->wpMaxs) + sizeof(tempMap);
00481 
00482     start = time(NULL);
00483 
00484     if (!l)
00485         Com_Error(ERR_DROP, "CMod_LoadRouting: No lump given");
00486 
00487     if (!l->filelen)
00488         Com_Error(ERR_DROP, "CMod_LoadRouting: Map has NO routing lump");
00489 
00490     assert((sX > -(PATHFINDING_WIDTH / 2)) && (sX < (PATHFINDING_WIDTH / 2)));
00491     assert((sY > -(PATHFINDING_WIDTH / 2)) && (sY < (PATHFINDING_WIDTH / 2)));
00492     assert((sZ >= 0) && (sZ < PATHFINDING_HEIGHT));
00493 
00494     source = base + l->fileofs;
00495 
00496     i = CMod_DeCompressRouting(&source, (byte*)tile->wpMins);
00497     length = i;
00498     i = CMod_DeCompressRouting(&source, (byte*)tile->wpMaxs);
00499     length += i;
00500     i = CMod_DeCompressRouting(&source, (byte*)tempMap);
00501     length += i;
00502 
00503     if (length != targetLength)
00504         Com_Error(ERR_DROP, "CMod_LoadRouting: Map has BAD routing lump; expected %i got %i", targetLength, length);
00505 
00506     /* endian swap possibly necessary */
00507     for (i = 0; i < 3; i++) {
00508         tile->wpMins[i] = LittleLong(tile->wpMins[i]);
00509         tile->wpMaxs[i] = LittleLong(tile->wpMaxs[i]);
00510     }
00511 
00512     Com_DPrintf(DEBUG_ROUTING, "Map:%s  Offset:(%i, %i, %i)\n", name, sX, sY, sZ);
00513     Com_DPrintf(DEBUG_ROUTING, "wpMins:(%i, %i, %i) wpMaxs:(%i, %i, %i)\n", tile->wpMins[0], tile->wpMins[1],
00514             tile->wpMins[2], tile->wpMaxs[0], tile->wpMaxs[1], tile->wpMaxs[2]);
00515 
00516     /* wpMins and wpMaxs have the map size data from the initial build.
00517      * Offset this by the given parameters so the stored values are in real coordinates. */
00518     tile->wpMins[0] += sX;
00519     tile->wpMins[1] += sY;
00520     tile->wpMins[2] += sZ;
00521     tile->wpMaxs[0] += sX;
00522     tile->wpMaxs[1] += sY;
00523     tile->wpMaxs[2] += sZ;
00524 
00525     Com_DPrintf(DEBUG_ROUTING, "Shifted wpMins:(%i, %i, %i) wpMaxs:(%i, %i, %i)\n", tile->wpMins[0],
00526             tile->wpMins[1], tile->wpMins[2], tile->wpMaxs[0], tile->wpMaxs[1], tile->wpMaxs[2]);
00527 
00528     /* Things that need to be done:
00529      * The floor, ceiling, and route data can be copied over from the map.
00530      * All data must be regenerated for cells with overlapping content or where new
00531      * model data is adjacent to a cell with existing model data. */
00532 
00533     /* Copy the routing information into our master table */
00534     minX = max(tile->wpMins[0], 0);
00535     minY = max(tile->wpMins[1], 0);
00536     minZ = max(tile->wpMins[2], 0);
00537     maxX = min(tile->wpMaxs[0], PATHFINDING_WIDTH - 1);
00538     maxY = min(tile->wpMaxs[1], PATHFINDING_WIDTH - 1);
00539     maxZ = min(tile->wpMaxs[2], PATHFINDING_HEIGHT - 1);
00540 
00541     assert(minX <= maxX);
00542     assert(minY <= maxY);
00543     assert(minZ <= maxZ);
00544 
00545     Com_DPrintf(DEBUG_ROUTING, "Tile bounds: (%i, %i, %i) to (%i, %i, %i)\n", minX, minY, minZ, maxX, maxY, maxZ);
00546     Com_DPrintf(DEBUG_ROUTING, "Source bounds: (%i, %i, %i) to (%i, %i, %i)\n", minX - sX, minY - sY, minZ - sZ,
00547             maxX - sX, maxY - sY, maxZ - sZ);
00548 
00549     for (size = 0; size < ACTOR_MAX_SIZE; size++)
00550         /* Adjust starting x and y by size to catch large actor cell overlap. */
00551         for (y = minY - size; y <= maxY; y++)
00552             for (x = minX - size; x <= maxX; x++) {
00553                 /* Just incase x or y start negative. */
00554                 if (x < 0 || y < 0)
00555                     continue;
00556                 for (z = minZ; z <= maxZ; z++) {
00557                     mapData->map[size].floor[z][y][x] = tempMap[size].floor[z - sZ][y - sY][x - sX];
00558                     mapData->map[size].ceil[z][y][x] = tempMap[size].ceil[z - sZ][y - sY][x - sX];
00559                     for (dir = 0; dir < CORE_DIRECTIONS; dir++) {
00560                         mapData->map[size].route[z][y][x][dir] = tempMap[size].route[z - sZ][y - sY][x - sX][dir];
00561                         mapData->map[size].stepup[z][y][x][dir] = tempMap[size].stepup[z - sZ][y - sY][x - sX][dir];
00562                     }
00563                 }
00564                 /* Update the reroute table */
00565                 if (!mapData->reroute[size][y][x]) {
00566                     mapData->reroute[size][y][x] = tile->idx + 1;
00567                 } else {
00568                     mapData->reroute[size][y][x] = ROUTING_NOT_REACHABLE;
00569                 }
00570             }
00571 
00572     Com_DPrintf(DEBUG_ROUTING, "Done copying data.\n");
00573 
00574     end = time(NULL);
00575     Com_DPrintf(DEBUG_ROUTING, "Loaded routing for tile %s in %5.1fs\n", name, end - start);
00576 }
00577 
00578 
00586 static void CMod_LoadEntityString (mapTile_t *tile, mapData_t *mapData, const byte *base, const lump_t * l, const vec3_t shift)
00587 {
00588     const char *token;
00589     const char *es;
00590     char keyname[256];
00591     vec3_t v;
00592     cBspModel_t *model = NULL;
00593 
00594     if (!l)
00595         Com_Error(ERR_DROP, "CMod_LoadEntityString: No lump given");
00596 
00597     if (!l->filelen)
00598         Com_Error(ERR_DROP, "CMod_LoadEntityString: Map has NO entity lump");
00599 
00600     if (l->filelen + 1 > MAX_MAP_ENTSTRING)
00601         Com_Error(ERR_DROP, "CMod_LoadEntityString: Map has too large entity lump");
00602 
00603     /* merge entitystring information */
00604     es = (const char *) (base + l->fileofs);
00605     while (1) {
00606         /* parse the opening brace */
00607         token = Com_Parse(&es);
00608         if (!es)
00609             break;
00610         if (token[0] != '{')
00611             Com_Error(ERR_DROP, "CMod_LoadEntityString: found %s when expecting {", token);
00612 
00613         /* new entity */
00614         Q_strcat(mapData->mapEntityString, "{ ", MAX_MAP_ENTSTRING);
00615 
00616         /* go through all the dictionary pairs */
00617         while (1) {
00618             /* parse key */
00619             token = Com_Parse(&es);
00620             if (token[0] == '}')
00621                 break;
00622             if (!es)
00623                 Com_Error(ERR_DROP, "CMod_LoadEntityString: EOF without closing brace");
00624 
00625             Q_strncpyz(keyname, token, sizeof(keyname));
00626 
00627             /* parse value */
00628             token = Com_Parse(&es);
00629             if (!es)
00630                 Com_Error(ERR_DROP, "CMod_LoadEntityString: EOF without closing brace");
00631 
00632             if (token[0] == '}')
00633                 Com_Error(ERR_DROP, "CMod_LoadEntityString: closing brace without data");
00634 
00635             /* alter value, if needed */
00636             if (!strcmp(keyname, "origin")) {
00637                 /* origins are shifted */
00638                 sscanf(token, "%f %f %f", &(v[0]), &(v[1]), &(v[2]));
00639                 VectorAdd(v, shift, v);
00640                 Q_strcat(mapData->mapEntityString, va("%s \"%f %f %f\" ", keyname, v[0], v[1], v[2]), MAX_MAP_ENTSTRING);
00641                 /* If we have a model, then unadjust it's mins and maxs. */
00642                 if (model) {
00643                     VectorSubtract(model->mins, shift, model->mins);
00644                     VectorSubtract(model->maxs, shift, model->maxs);
00645                     model = NULL; /* reset it, or the next origin will shift it again */
00646                 }
00647             } else if (!strcmp(keyname, "model") && token[0] == '*') {
00648                 /* adapt inline model number */
00649                 int num = atoi(token + 1);
00650                 /* Get the model */
00651                 model = &tile->models[NUM_REGULAR_MODELS + num - 1];
00652                 /* Now update the model number to reflect prior tiles loaded. */
00653                 num += mapData->numInline;
00654                 Q_strcat(mapData->mapEntityString, va("%s *%i ", keyname, num), MAX_MAP_ENTSTRING);
00655             } else if (!strcmp(keyname, "targetname") || !strcmp(keyname, "target")) {
00656                 Q_strcat(mapData->mapEntityString, va("%s \"%s-%i\" ", keyname, token, tile->idx), MAX_MAP_ENTSTRING);
00657             } else {
00658                 /* just store key and value */
00659                 Q_strcat(mapData->mapEntityString, va("%s \"%s\" ", keyname, token), MAX_MAP_ENTSTRING);
00660             }
00661         }
00662 
00663         /* finish entity */
00664         Q_strcat(mapData->mapEntityString, "} ", MAX_MAP_ENTSTRING);
00665     }
00666 }
00667 
00672 static void CMod_LoadLighting (mapTile_t *tile, const byte *base, const lump_t * l)
00673 {
00674 #if 0
00675     tile->lightdata = Mem_PoolAlloc(l->filelen, com_cmodelSysPool, 0);
00676     memcpy(tile->lightdata, base + l->fileofs, l->filelen);
00677 #endif
00678 }
00679 
00684 static void CM_InitBoxHull (mapTile_t *tile)
00685 {
00686     int i;
00687 
00688     tile->box_headnode = tile->numnodes;
00689     tile->box_planes = &tile->planes[tile->numplanes];
00690     /* sanity check if you only use one maptile => no map assembly */
00691     if (tile->idx == 1 && (tile->numnodes + 6 > MAX_MAP_NODES
00692         || tile->numbrushes + 1 > MAX_MAP_BRUSHES
00693         || tile->numleafbrushes + 1 > MAX_MAP_LEAFBRUSHES
00694         || tile->numbrushsides + 6 > MAX_MAP_BRUSHSIDES
00695         || tile->numplanes + 12 > MAX_MAP_PLANES))
00696         Com_Error(ERR_DROP, "Not enough room for box tree");
00697 
00698     tile->box_brush = &tile->brushes[tile->numbrushes];
00699     tile->box_brush->numsides = 6;
00700     tile->box_brush->firstbrushside = tile->numbrushsides;
00701     tile->box_brush->contentFlags = CONTENTS_WEAPONCLIP;
00702 
00703     tile->box_leaf = &tile->leafs[tile->numleafs];
00704     tile->box_leaf->contentFlags = CONTENTS_WEAPONCLIP;
00705     tile->box_leaf->firstleafbrush = tile->numleafbrushes;
00706     tile->box_leaf->numleafbrushes = 1;
00707 
00708     tile->leafbrushes[tile->numleafbrushes] = tile->numbrushes;
00709 
00710     /* each side */
00711     for (i = 0; i < 6; i++) {
00712         const int side = i & 1;
00713         cBspNode_t *c;
00714         cBspPlane_t *p;
00715         cBspBrushSide_t *s;
00716 
00717         /* brush sides */
00718         s = &tile->brushsides[tile->numbrushsides + i];
00719         s->plane = tile->planes + (tile->numplanes + i * 2 + side);
00720         s->surface = &nullSurface;
00721 
00722         /* nodes */
00723         c = &tile->nodes[tile->box_headnode + i];
00724         c->plane = tile->planes + (tile->numplanes + i * 2);
00725         c->children[side] = -1 - tile->emptyleaf;
00726         if (i != 5)
00727             c->children[side ^ 1] = tile->box_headnode + i + 1;
00728         else
00729             c->children[side ^ 1] = LEAFNODE - tile->numleafs;
00730 
00731         /* planes */
00732         p = &tile->box_planes[i * 2];
00733         p->type = i >> 1;
00734         VectorClear(p->normal);
00735         p->normal[i >> 1] = 1;
00736 
00737         p = &tile->box_planes[i * 2 + 1];
00738         p->type = PLANE_ANYX + (i >> 1);
00739         VectorClear(p->normal);
00740         p->normal[i >> 1] = -1;
00741     }
00742 }
00743 
00758 static void CM_AddMapTile (const char *name, qboolean day, int sX, int sY, byte sZ, mapData_t *mapData, mapTiles_t *mapTiles)
00759 {
00760     char filename[MAX_QPATH];
00761     unsigned checksum;
00762     byte *buf;
00763     unsigned int i;
00764     int length;
00765     dBspHeader_t header;
00766     /* use for random map assembly for shifting origins and so on */
00767     vec3_t shift;
00768     const byte *base;
00769     mapTile_t *tile;
00770 
00771     Com_DPrintf(DEBUG_ENGINE, "CM_AddMapTile: %s at %i,%i,%i\n", name, sX, sY, sZ);
00772     assert(name);
00773     assert(name[0]);
00774     assert((sX > -(PATHFINDING_WIDTH / 2)) && (sX < (PATHFINDING_WIDTH / 2)));
00775     assert((sY > -(PATHFINDING_WIDTH / 2)) && (sY < (PATHFINDING_WIDTH / 2)));
00776     assert(sZ < PATHFINDING_HEIGHT);
00777 
00778     /* load the file */
00779     Com_sprintf(filename, sizeof(filename), "maps/%s.bsp", name);
00780     length = FS_LoadFile(filename, &buf);
00781     if (!buf)
00782         Com_Error(ERR_DROP, "Couldn't load %s", filename);
00783 
00784     checksum = LittleLong(Com_BlockChecksum(buf, length));
00785 
00786     header = *(dBspHeader_t *) buf;
00787     for (i = 0; i < sizeof(header) / 4; i++)
00788         ((int *) &header)[i] = LittleLong(((int *) &header)[i]);
00789 
00790     if (header.version != BSPVERSION)
00791         Com_Error(ERR_DROP, "CM_AddMapTile: %s has wrong version number (%i should be %i)", name, header.version, BSPVERSION);
00792 
00793     base = (const byte *) buf;
00794 
00795     /* init */
00796     if (mapTiles->numTiles >= MAX_MAPTILES)
00797         Com_Error(ERR_FATAL, "CM_AddMapTile: too many tiles loaded %i", mapTiles->numTiles);
00798 
00799     tile = &(mapTiles->mapTiles[mapTiles->numTiles]);
00800     memset(tile, 0, sizeof(*tile));
00801     tile->idx = mapTiles->numTiles;
00802     Q_strncpyz(tile->name, name, sizeof(tile->name));
00803 
00804     /* pathfinding and the like must be shifted on the worldplane when we
00805      * are assembling a map */
00806     VectorSet(shift, sX * UNIT_SIZE, sY * UNIT_SIZE, sZ * UNIT_HEIGHT);
00807 
00808     /* load into heap */
00809     CMod_LoadSurfaces(tile, base, &header.lumps[LUMP_TEXINFO]);
00810     CMod_LoadLeafs(tile, base, &header.lumps[LUMP_LEAFS]);
00811     CMod_LoadLeafBrushes(tile, base, &header.lumps[LUMP_LEAFBRUSHES]);
00812     CMod_LoadPlanes(tile, base, &header.lumps[LUMP_PLANES], shift);
00813     CMod_LoadBrushes(tile, base, &header.lumps[LUMP_BRUSHES]);
00814     CMod_LoadBrushSides(tile, base, &header.lumps[LUMP_BRUSHSIDES]);
00815     CMod_LoadSubmodels(tile, base, &header.lumps[LUMP_MODELS], shift);
00816     CMod_LoadNodes(tile, base, &header.lumps[LUMP_NODES], shift);
00817     CMod_LoadEntityString(tile, mapData, base, &header.lumps[LUMP_ENTITIES], shift);
00818     if (day)
00819         CMod_LoadLighting(tile, base, &header.lumps[LUMP_LIGHTING_DAY]);
00820     else
00821         CMod_LoadLighting(tile, base, &header.lumps[LUMP_LIGHTING_NIGHT]);
00822 
00823     CM_InitBoxHull(tile);
00824     CM_MakeTracingNodes(tile);
00825 
00826     mapData->numInline += tile->nummodels - NUM_REGULAR_MODELS;
00827 
00828     CMod_LoadRouting(tile, mapData, base, name, &header.lumps[LUMP_ROUTING], sX, sY, sZ);
00829 
00830     /* now increase the amount of loaded tiles */
00831     mapTiles->numTiles++;
00832 
00833     /* Now find the map bounds with the updated numTiles. */
00834     /* calculate new border after merge */
00835     RT_GetMapSize(mapTiles, mapData->mapMin, mapData->mapMax);
00836 
00837     FS_FreeFile(buf);
00838 
00839     mapData->mapChecksum += checksum;
00840 }
00841 
00842 static void CMod_RerouteMap (mapTiles_t *mapTiles, mapData_t *mapData)
00843 {
00844     actorSizeEnum_t size;
00845     int x, y, z, dir;
00846     int i;
00847     pos3_t mins, maxs;
00848     double start, end;
00849 
00850     start = time(NULL);
00851 
00852     VecToPos(mapData->mapMin, mins);
00853     VecToPos(mapData->mapMax, maxs);
00854 
00855     /* fit min/max into the world size */
00856     maxs[0] = min(maxs[0], PATHFINDING_WIDTH - 1);
00857     maxs[1] = min(maxs[1], PATHFINDING_WIDTH - 1);
00858     maxs[2] = min(maxs[2], PATHFINDING_HEIGHT - 1);
00859     for (i = 0; i < 3; i++)
00860         mins[i] = max(mins[i], 0);
00861 
00862     Com_DPrintf(DEBUG_PATHING, "rerouting (%i %i %i) (%i %i %i)\n",
00863         (int)mins[0], (int)mins[1], (int)mins[2],
00864         (int)maxs[0], (int)maxs[1], (int)maxs[2]);
00865 
00866     /* Floor pass */
00867     for (size = ACTOR_SIZE_INVALID; size < ACTOR_MAX_SIZE; size++) {
00868         for (y = mins[1]; y <= maxs[1]; y++) {
00869             for (x = mins[0]; x <= maxs[0]; x++) {
00870                 if (mapData->reroute[size][y][x] == ROUTING_NOT_REACHABLE) {
00871                     /* Com_Printf("Tracing floor (%i %i s:%i)\n", x, y, size); */
00872                     for (z = maxs[2]; z >= mins[2]; z--) {
00873                         const int newZ = RT_CheckCell(mapTiles, mapData->map, size + 1, x, y, z, NULL);
00874                         assert(newZ <= z);
00875                         z = newZ;
00876                     }
00877                 }
00878             }
00879         }
00880     }
00881 
00882     /* Wall pass */
00883     for (size = ACTOR_SIZE_INVALID; size < ACTOR_MAX_SIZE; size++) {
00884         for (y = mins[1]; y <= maxs[1]; y++) {
00885             for (x = mins[0]; x <= maxs[0]; x++) {
00886                 const byte tile = mapData->reroute[size][y][x];
00887                 if (tile) {
00890                     /* Not needed until inverse tracing works again.
00891                      * for (dir = 0; dir < CORE_DIRECTIONS; dir += 2) { */
00892                     for (dir = 0; dir < CORE_DIRECTIONS; dir++) {
00893                         const int dx = x + dvecs[dir][0];
00894                         const int dy = y + dvecs[dir][1];
00895                         int tile2; 
00896                         /* Skip if the destination is out of bounds. */
00897                         if (dx < 0 || dx >= PATHFINDING_WIDTH || dy < 0 || dy >= PATHFINDING_WIDTH)
00898                             continue;
00899                         tile2 = mapData->reroute[size][dy][dx];
00900                         /* Both cells are present and if either cell is ROUTING_NOT_REACHABLE or if the cells are different. */
00901                         if (tile2 && (tile2 == ROUTING_NOT_REACHABLE || tile2 != tile)) {
00904                             /* Com_Printf("Tracing passage (%i %i s:%i d:%i)\n", x, y, size, dir); */
00905                             RT_UpdateConnectionColumn(mapTiles, mapData->map, size + 1, x, y, dir, NULL);
00906                         }
00907                     }
00908                 }
00909             }
00910         }
00911     }
00912     end = time(NULL);
00913     Com_Printf("Rerouted for RMA in %5.1fs\n", end - start);
00914 }
00915 
00928 void CM_LoadMap (const char *tiles, qboolean day, const char *pos, mapData_t *mapData, mapTiles_t *mapTiles)
00929 {
00930     const char *token;
00931     char name[MAX_VAR];
00932     char base[MAX_QPATH];
00933     int i;
00934 
00935     Mem_FreePool(com_cmodelSysPool);
00936 
00937     /* init */
00938     base[0] = 0;
00939 
00940     /* Reset the map related data */
00941     memset(mapData, 0, sizeof(*mapData));
00942     memset(mapTiles, 0, sizeof(*mapTiles));
00943 
00944     if (pos && *pos)
00945         Com_Printf("CM_LoadMap: \"%s\" \"%s\"\n", tiles, pos);
00946 
00947     /* load tiles */
00948     while (tiles) {
00949         /* get tile name */
00950         token = Com_Parse(&tiles);
00951         if (!tiles) {
00952             CMod_RerouteMap(mapTiles, mapData);
00953             return;
00954         }
00955 
00956         /* get base path */
00957         if (token[0] == '-') {
00958             Q_strncpyz(base, token + 1, sizeof(base));
00959             continue;
00960         }
00961 
00962         /* get tile name */
00963         Com_DPrintf(DEBUG_ENGINE, "CM_LoadMap: token: %s\n", token);
00964         if (token[0] == '+')
00965             Com_sprintf(name, sizeof(name), "%s%s", base, token + 1);
00966         else
00967             Q_strncpyz(name, token, sizeof(name));
00968 
00969         if (pos && pos[0]) {
00970             ipos3_t sh;
00971             /* get position and add a tile */
00972             for (i = 0; i < 3; i++) {
00973                 token = Com_Parse(&pos);
00974                 if (!pos)
00975                     Com_Error(ERR_DROP, "CM_LoadMap: invalid positions");
00976                 sh[i] = atoi(token);
00977             }
00978             if (sh[0] <= -(PATHFINDING_WIDTH / 2) || sh[0] >= PATHFINDING_WIDTH / 2)
00979                 Com_Error(ERR_DROP, "CM_LoadMap: invalid x position given: %i\n", sh[0]);
00980             if (sh[1] <= -(PATHFINDING_WIDTH / 2) || sh[1] >= PATHFINDING_WIDTH / 2)
00981                 Com_Error(ERR_DROP, "CM_LoadMap: invalid y position given: %i\n", sh[1]);
00982             if (sh[2] >= PATHFINDING_HEIGHT)
00983                 Com_Error(ERR_DROP, "CM_LoadMap: invalid z position given: %i\n", sh[2]);
00984             CM_AddMapTile(name, day, sh[0], sh[1], sh[2], mapData, mapTiles);
00985         } else {
00986             /* load only a single tile, if no positions are specified */
00987             CM_AddMapTile(name, day, 0, 0, 0, mapData, mapTiles);
00988             return;
00989         }
00990     }
00991 
00992     Com_Error(ERR_DROP, "CM_LoadMap: invalid tile names");
00993 }
00994 
01001 cBspModel_t *CM_InlineModel (mapTiles_t *mapTiles, const char *name)
01002 {
01003     int i, num;
01004 
01005     /* we only want inline models here */
01006     if (!name || name[0] != '*')
01007         Com_Error(ERR_DROP, "CM_InlineModel: bad name: '%s'", name ? name : "");
01008     /* skip the '*' character and get the inline model number */
01009     num = atoi(name + 1) - 1;
01010     if (num < 0 || num >= MAX_MODELS)
01011         Com_Error(ERR_DROP, "CM_InlineModel: bad number %i - max inline models are %i", num, MAX_MODELS);
01012 
01013     /* search all the loaded tiles for the given inline model */
01014     for (i = 0; i < mapTiles->numTiles; i++) {
01015         const int models = mapTiles->mapTiles[i].nummodels - NUM_REGULAR_MODELS;
01016         assert(models >= 0);
01017 
01018         if (num >= models)
01019             num -= models;
01020         else
01021             return &(mapTiles->mapTiles[i].models[NUM_REGULAR_MODELS + num]);
01022     }
01023 
01024     Com_Error(ERR_DROP, "CM_InlineModel: Error cannot find model '%s'\n", name);
01025 }
01026 
01036 void CM_SetInlineModelOrientation (mapTiles_t *mapTiles, const char *name, const vec3_t origin, const vec3_t angles)
01037 {
01038     cBspModel_t *model = CM_InlineModel(mapTiles, name);
01039     assert(model);
01040     VectorCopy(origin, model->origin);
01041     VectorCopy(angles, model->angles);
01042 }

Generated by  doxygen 1.6.2