bspfile.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 "shared.h"
00027 #include "bspfile.h"
00028 #include "scriplib.h"
00029 #include "../bsp.h"
00030 
00036 byte *CompressRouting (byte *dataStart, byte *destStart, int l)
00037 {
00038     int c;
00039     byte val;
00040     byte *data, *dend, *dest_p, *count_p;
00041 
00042     dest_p = destStart;
00043     data = dataStart;
00044     dend = dataStart + l;
00045 
00046     while (data < dend) {
00047         if (data + 1 < dend && *data == *(data + 1)) {
00048             /* repetitions */
00049             val = *data++;
00050             data++; /* Advance data again.  The first two bytes are identical!!! */
00051             c = 0; /* This means 2 bytes are the same.  Total bytes the same is 2 + c */
00052             /* Loop while the piece of data being looked at equals val */
00053             while (data + 1 < dend && val == *(data)) {
00054                 if (c >= SCHAR_MAX) /* must fit into one byte */
00055                     break;
00056                 data++;
00057                 c++;
00058             }
00059             count_p = dest_p;
00060             *dest_p++ = (byte)(c) | 0x80;
00061             *dest_p++ = val;
00062         } else {
00063             /* identities */
00064             count_p = dest_p++;
00065             c = 0;
00066             while ((data + 1 < dend && *data != *(data + 1)) || data == dend - 1) {
00067                 if (c >= SCHAR_MAX) /* must fit into one byte */
00068                     break;
00069                 *dest_p++ = *data++;
00070                 c++;
00071             }
00072             *count_p = (byte)c;
00073         }
00074     }
00075 
00076     /* terminate compressed data */
00077     *dest_p++ = 0;
00078 
00079     return dest_p;
00080 }
00081 
00085 static void SwapBSPFile (void)
00086 {
00087     int i, j, k;
00088 
00089     /* models    */
00090     for (i = 0; i < curTile->nummodels; i++) {
00091         dBspModel_t *d = &curTile->models[i];
00092 
00093         d->firstface = LittleLong(d->firstface);
00094         d->numfaces = LittleLong(d->numfaces);
00095         d->headnode = LittleLong(d->headnode);
00096 
00097         for (j = 0; j < 3; j++) {
00098             d->mins[j] = LittleFloat(d->mins[j]);
00099             d->maxs[j] = LittleFloat(d->maxs[j]);
00100             d->origin[j] = LittleFloat(d->origin[j]);
00101         }
00102     }
00103 
00104     /* vertexes */
00105     for (i = 0; i < curTile->numvertexes; i++) {
00106         for (j = 0; j < 3; j++)
00107             curTile->vertexes[i].point[j] = LittleFloat(curTile->vertexes[i].point[j]);
00108     }
00109 
00110     /* planes */
00111     for (i = 0; i < curTile->numplanes; i++) {
00112         for (j = 0; j < 3; j++)
00113             curTile->planes[i].normal[j] = LittleFloat(curTile->planes[i].normal[j]);
00114         curTile->planes[i].dist = LittleFloat(curTile->planes[i].dist);
00115         curTile->planes[i].type = LittleLong(curTile->planes[i].type);
00116     }
00117 
00118     /* texinfos */
00119     for (i = 0; i < curTile->numtexinfo; i++) {
00120         for (j = 0; j < 2; j++)
00121             for (k = 0; k < 4; k++)
00122                 curTile->texinfo[i].vecs[j][k] = LittleFloat(curTile->texinfo[i].vecs[j][k]);
00123         curTile->texinfo[i].surfaceFlags = LittleLong(curTile->texinfo[i].surfaceFlags);
00124         curTile->texinfo[i].value = LittleLong(curTile->texinfo[i].value);
00125     }
00126 
00127     /* faces */
00128     for (i = 0; i < curTile->numfaces; i++) {
00129         curTile->faces[i].texinfo = LittleShort(curTile->faces[i].texinfo);
00130         curTile->faces[i].planenum = LittleShort(curTile->faces[i].planenum);
00131         curTile->faces[i].side = LittleShort(curTile->faces[i].side);
00132         for (j = 0; j < LIGHTMAP_MAX; j++)
00133             curTile->faces[i].lightofs[j] = LittleLong(curTile->faces[i].lightofs[j]);
00134         curTile->faces[i].firstedge = LittleLong(curTile->faces[i].firstedge);
00135         curTile->faces[i].numedges = LittleShort(curTile->faces[i].numedges);
00136     }
00137 
00138     /* nodes */
00139     for (i = 0; i < curTile->numnodes; i++) {
00140         /* planenum might be -1 here - special case for pathfinding nodes */
00141         curTile->nodes[i].planenum = LittleLong(curTile->nodes[i].planenum);
00142         for (j = 0; j < 3; j++) {
00143             curTile->nodes[i].mins[j] = LittleShort(curTile->nodes[i].mins[j]);
00144             curTile->nodes[i].maxs[j] = LittleShort(curTile->nodes[i].maxs[j]);
00145         }
00146         curTile->nodes[i].children[0] = LittleLong(curTile->nodes[i].children[0]);
00147         curTile->nodes[i].children[1] = LittleLong(curTile->nodes[i].children[1]);
00148         curTile->nodes[i].firstface = LittleShort(curTile->nodes[i].firstface);
00149         curTile->nodes[i].numfaces = LittleShort(curTile->nodes[i].numfaces);
00150     }
00151 
00152     /* leafs */
00153     for (i = 0; i < curTile->numleafs; i++) {
00154         curTile->leafs[i].contentFlags = LittleLong(curTile->leafs[i].contentFlags);
00155         curTile->leafs[i].area = LittleShort(curTile->leafs[i].area);
00156         for (j = 0; j < 3; j++) {
00157             curTile->leafs[i].mins[j] = LittleShort(curTile->leafs[i].mins[j]);
00158             curTile->leafs[i].maxs[j] = LittleShort(curTile->leafs[i].maxs[j]);
00159         }
00160 
00161         curTile->leafs[i].firstleafbrush = LittleShort(curTile->leafs[i].firstleafbrush);
00162         curTile->leafs[i].numleafbrushes = LittleShort(curTile->leafs[i].numleafbrushes);
00163     }
00164 
00165     /* leafbrushes */
00166     for (i = 0; i < curTile->numleafbrushes; i++)
00167         curTile->leafbrushes[i] = LittleShort(curTile->leafbrushes[i]);
00168 
00169     /* surfedges */
00170     for (i = 0; i < curTile->numsurfedges; i++)
00171         curTile->surfedges[i] = LittleLong(curTile->surfedges[i]);
00172 
00173     /* edges */
00174     for (i = 0; i < curTile->numedges; i++) {
00175         curTile->edges[i].v[0] = LittleShort(curTile->edges[i].v[0]);
00176         curTile->edges[i].v[1] = LittleShort(curTile->edges[i].v[1]);
00177     }
00178 
00179     /* dbrushes */
00180     for (i = 0; i < curTile->numbrushes; i++) {
00181         curTile->dbrushes[i].firstbrushside = LittleLong(curTile->dbrushes[i].firstbrushside);
00182         curTile->dbrushes[i].numsides = LittleLong(curTile->dbrushes[i].numsides);
00183         curTile->dbrushes[i].contentFlags = LittleLong(curTile->dbrushes[i].contentFlags);
00184     }
00185 
00186     /* brushes */
00187     for (i = 0; i < curTile->numbrushes; i++) {
00188         curTile->brushes[i].firstbrushside = LittleLong(curTile->brushes[i].firstbrushside);
00189         curTile->brushes[i].numsides = LittleLong(curTile->brushes[i].numsides);
00190         curTile->brushes[i].contentFlags = LittleLong(curTile->brushes[i].contentFlags);
00191     }
00192 
00193     /* brushsides */
00194     for (i = 0; i < curTile->numbrushsides; i++) {
00195         curTile->brushsides[i].planenum = LittleShort(curTile->brushsides[i].planenum);
00196         curTile->brushsides[i].texinfo = LittleShort(curTile->brushsides[i].texinfo);
00197     }
00198 }
00199 
00200 
00201 static dBspHeader_t *header;
00202 
00203 static int CopyLump (int lump, void *dest, int size)
00204 {
00205     const int length = header->lumps[lump].filelen;
00206     const int ofs = header->lumps[lump].fileofs;
00207 
00208     if (length == 0)
00209         return 0;
00210     if (length % size)
00211         Sys_Error("LoadBSPFile: odd lump size");
00212 
00213     memcpy(dest, (byte *)header + ofs, length);
00214 
00215     return length / size;
00216 }
00217 
00221 void LoadBSPFile (const char *filename)
00222 {
00223     int size;
00224     unsigned int i;
00225 
00226     /* Create this shortcut to mapTiles[0] */
00227     curTile = &mapTiles.mapTiles[0];
00228     /* Set the number of tiles to 1. */
00229     mapTiles.numTiles = 1;
00230 
00231     /* load the file header */
00232     size = FS_LoadFile(filename, (byte **)&header);
00233     if (size == -1)
00234         Sys_Error("'%s' doesn't exist", filename);
00235 
00236     /* swap the header */
00237     for (i = 0; i < sizeof(dBspHeader_t) / 4; i++)
00238         ((int *)header)[i] = LittleLong(((int *)header)[i]);
00239 
00240     if (header->ident != IDBSPHEADER)
00241         Sys_Error("%s is not a IBSP file", filename);
00242     if (header->version != BSPVERSION)
00243         Sys_Error("%s is version %i, not %i", filename, header->version, BSPVERSION);
00244 
00245     curTile->nummodels = CopyLump(LUMP_MODELS, curTile->models, sizeof(dBspModel_t));
00246     curTile->numvertexes = CopyLump(LUMP_VERTEXES, curTile->vertexes, sizeof(dBspVertex_t));
00247     curTile->numplanes = CopyLump(LUMP_PLANES, curTile->planes, sizeof(dBspPlane_t));
00248     curTile->numleafs = CopyLump(LUMP_LEAFS, curTile->leafs, sizeof(dBspLeaf_t));
00249     curTile->numnormals = CopyLump(LUMP_NORMALS, curTile->normals, sizeof(dBspNormal_t));
00250     curTile->numnodes = CopyLump(LUMP_NODES, curTile->nodes, sizeof(dBspNode_t));
00251     curTile->numtexinfo = CopyLump(LUMP_TEXINFO, curTile->texinfo, sizeof(dBspTexinfo_t));
00252     curTile->numfaces = CopyLump(LUMP_FACES, curTile->faces, sizeof(dBspSurface_t));
00253     curTile->numleafbrushes = CopyLump(LUMP_LEAFBRUSHES, curTile->leafbrushes, sizeof(curTile->leafbrushes[0]));
00254     curTile->numsurfedges = CopyLump(LUMP_SURFEDGES, curTile->surfedges, sizeof(curTile->surfedges[0]));
00255     curTile->numedges = CopyLump(LUMP_EDGES, curTile->edges, sizeof(dBspEdge_t));
00256     curTile->numbrushes = CopyLump(LUMP_BRUSHES, curTile->dbrushes, sizeof(dBspBrush_t));
00257     curTile->numbrushsides = CopyLump(LUMP_BRUSHSIDES, curTile->brushsides, sizeof(dBspBrushSide_t));
00258     curTile->routedatasize = CopyLump(LUMP_ROUTING, curTile->routedata, 1);
00259     curTile->lightdatasize[LIGHTMAP_NIGHT] = CopyLump(LUMP_LIGHTING_NIGHT, curTile->lightdata[LIGHTMAP_NIGHT], 1);
00260     curTile->lightdatasize[LIGHTMAP_DAY] = CopyLump(LUMP_LIGHTING_DAY, curTile->lightdata[LIGHTMAP_DAY], 1);
00261     curTile->entdatasize = CopyLump(LUMP_ENTITIES, curTile->entdata, 1);
00262 
00263     /* Because the tracing functions use cBspBrush_t and not dBspBrush_t,
00264      * copy data from curTile->dbrushes into curTile->cbrushes */
00265     memset(curTile->brushes, 0, MAX_MAP_BRUSHES * sizeof(cBspBrush_t));
00266     for (i = 0; i < curTile->numbrushes; i++) {
00267         curTile->brushes[i].firstbrushside = curTile->dbrushes[i].firstbrushside;
00268         curTile->brushes[i].numsides = curTile->dbrushes[i].numsides;
00269         curTile->brushes[i].contentFlags = curTile->dbrushes[i].contentFlags;
00270     }
00271 
00272     /* everything has been copied out */
00273     FS_FreeFile(header);
00274 
00275     /* swap everything */
00276     SwapBSPFile();
00277 }
00278 
00283 static inline void AddLump (qFILE *bspfile, dBspHeader_t *header, int lumpnum, void *data, int len)
00284 {
00285     lump_t *lump;
00286 
00287     lump = &header->lumps[lumpnum];
00288 
00289     lump->fileofs = LittleLong(ftell(bspfile->f));
00290     lump->filelen = LittleLong(len);
00291     /* 4 byte align */
00292     FS_Write(data, (len + 3) &~ 3, bspfile);
00293 }
00294 
00299 long WriteBSPFile (const char *filename)
00300 {
00301     qFILE bspfile;
00302     dBspHeader_t outheader;
00303     long size;
00304 
00305     memset(&outheader, 0, sizeof(outheader));
00306     memset(&bspfile, 0, sizeof(bspfile));
00307 
00308     SwapBSPFile();
00309 
00310     outheader.ident = LittleLong(IDBSPHEADER);
00311     outheader.version = LittleLong(BSPVERSION);
00312 
00313     FS_OpenFile(filename, &bspfile, FILE_WRITE);
00314     if (!bspfile.f)
00315         Sys_Error("Could not write bsp file");
00316     FS_Write(&outheader, sizeof(dBspHeader_t), &bspfile);   /* overwritten later */
00317 
00318     AddLump(&bspfile, &outheader, LUMP_PLANES, curTile->planes, curTile->numplanes * sizeof(dBspPlane_t));
00319     AddLump(&bspfile, &outheader, LUMP_LEAFS, curTile->leafs, curTile->numleafs * sizeof(dBspLeaf_t));
00320     AddLump(&bspfile, &outheader, LUMP_VERTEXES, curTile->vertexes, curTile->numvertexes * sizeof(dBspVertex_t));
00321     AddLump(&bspfile, &outheader, LUMP_NORMALS, curTile->normals, curTile->numnormals * sizeof(dBspNormal_t));
00322     AddLump(&bspfile, &outheader, LUMP_NODES, curTile->nodes, curTile->numnodes * sizeof(dBspNode_t));
00323     AddLump(&bspfile, &outheader, LUMP_TEXINFO, curTile->texinfo, curTile->numtexinfo * sizeof(dBspTexinfo_t));
00324     AddLump(&bspfile, &outheader, LUMP_FACES, curTile->faces, curTile->numfaces * sizeof(dBspSurface_t));
00325     AddLump(&bspfile, &outheader, LUMP_BRUSHES, curTile->dbrushes, curTile->numbrushes * sizeof(dBspBrush_t));
00326     AddLump(&bspfile, &outheader, LUMP_BRUSHSIDES, curTile->brushsides, curTile->numbrushsides * sizeof(dBspBrushSide_t));
00327     AddLump(&bspfile, &outheader, LUMP_LEAFBRUSHES, curTile->leafbrushes, curTile->numleafbrushes * sizeof(curTile->leafbrushes[0]));
00328     AddLump(&bspfile, &outheader, LUMP_SURFEDGES, curTile->surfedges, curTile->numsurfedges * sizeof(curTile->surfedges[0]));
00329     AddLump(&bspfile, &outheader, LUMP_EDGES, curTile->edges, curTile->numedges * sizeof(dBspEdge_t));
00330     AddLump(&bspfile, &outheader, LUMP_MODELS, curTile->models, curTile->nummodels * sizeof(dBspModel_t));
00331     AddLump(&bspfile, &outheader, LUMP_LIGHTING_NIGHT, curTile->lightdata[0], curTile->lightdatasize[0]);
00332     AddLump(&bspfile, &outheader, LUMP_LIGHTING_DAY, curTile->lightdata[1], curTile->lightdatasize[1]);
00333     AddLump(&bspfile, &outheader, LUMP_ROUTING, curTile->routedata, curTile->routedatasize);
00334     AddLump(&bspfile, &outheader, LUMP_ENTITIES, curTile->entdata, curTile->entdatasize);
00335     size = ftell(bspfile.f);
00336 
00337     fseek(bspfile.f, 0L, SEEK_SET);
00338     FS_Write(&outheader, sizeof(outheader), &bspfile);
00339     FS_CloseFile(&bspfile);
00340 
00341     SwapBSPFile();
00342 
00343     return size;
00344 }
00345 
00349 void PrintBSPFileSizes (void)
00350 {
00351     if (!num_entities)
00352         ParseEntities();
00353 
00354     Com_Printf("amout type         size in bytes\n");
00355     Com_Printf("================================\n");
00356     Com_Printf("%5i models            %7i\n", curTile->nummodels, (int)(curTile->nummodels * sizeof(cBspModel_t)));
00357     Com_Printf("%5i brushes           %7i\n", curTile->numbrushes, (int)(curTile->numbrushes * sizeof(dBspBrush_t)));
00358     Com_Printf("%5i brushsides        %7i\n", curTile->numbrushsides, (int)(curTile->numbrushsides * sizeof(dBspBrushSide_t)));
00359     Com_Printf("%5i planes            %7i\n", curTile->numplanes, (int)(curTile->numplanes * sizeof(dBspPlane_t)));
00360     Com_Printf("%5i texinfo           %7i\n", curTile->numtexinfo, (int)(curTile->numtexinfo * sizeof(dBspTexinfo_t)));
00361     Com_Printf("%5i entdata           %7i\n", num_entities, curTile->entdatasize);
00362 
00363     Com_Printf("\n");
00364 
00365     Com_Printf("%5i normales          %7i\n", curTile->numnormals, (int)(curTile->numnormals * sizeof(dBspNormal_t)));
00366     Com_Printf("%5i vertexes          %7i\n", curTile->numvertexes, (int)(curTile->numvertexes * sizeof(dBspVertex_t)));
00367     Com_Printf("%5i nodes             %7i\n", curTile->numnodes, (int)(curTile->numnodes * sizeof(dBspNode_t)));
00368     Com_Printf("%5i faces             %7i\n", curTile->numfaces, (int)(curTile->numfaces * sizeof(dBspSurface_t)));
00369     Com_Printf("%5i leafs             %7i\n", curTile->numleafs, (int)(curTile->numleafs * sizeof(dBspLeaf_t)));
00370     Com_Printf("%5i leafbrushes       %7i\n", curTile->numleafbrushes, (int)(curTile->numleafbrushes * sizeof(curTile->leafbrushes[0])));
00371     Com_Printf("%5i surfedges         %7i\n", curTile->numsurfedges, (int)(curTile->numsurfedges * sizeof(curTile->surfedges[0])));
00372     Com_Printf("%5i edges             %7i\n", curTile->numedges, (int)(curTile->numedges * sizeof(dBspEdge_t)));
00373     Com_Printf("night lightdata         %7i\n", curTile->lightdatasize[0]);
00374     Com_Printf("  day lightdata         %7i\n", curTile->lightdatasize[1]);
00375     Com_Printf("      routedata         %7i\n", curTile->routedatasize);
00376 }
00377 
00378 
00379 int num_entities;
00380 entity_t entities[MAX_MAP_ENTITIES];
00381 
00387 static void StripTrailingWhitespaces (char *str)
00388 {
00389     char *s;
00390 
00391     s = str + strlen(str) - 1;
00392     while (s >= str && *s <= ' ') {
00393         *s = '\0';
00394         s--;
00395     }
00396 }
00397 
00405 epair_t *ParseEpair (void)
00406 {
00407     epair_t *e;
00408 
00409     e = Mem_Alloc(sizeof(*e));
00410 
00411     if (strlen(parsedToken) >= MAX_KEY - 1)
00412         Sys_Error("ParseEpar: token too long");
00413     e->key = Mem_StrDup(parsedToken);
00414     GetToken(qfalse);
00415     if (strlen(parsedToken) >= MAX_VALUE - 1)
00416         Sys_Error("ParseEpar: token too long");
00417     e->value = Mem_StrDup(parsedToken);
00418 
00419     /* strip trailing spaces */
00420     StripTrailingWhitespaces(e->key);
00421     StripTrailingWhitespaces(e->value);
00422 
00423     return e;
00424 }
00425 
00426 
00430 static entity_t* ParseEntity (void)
00431 {
00432     entity_t *mapent;
00433 
00434     if (!GetToken(qtrue))
00435         return NULL;
00436 
00437     if (parsedToken[0] != '{')
00438         Sys_Error("ParseEntity: { not found");
00439 
00440     if (num_entities >= MAX_MAP_ENTITIES)
00441         Sys_Error("num_entities >= MAX_MAP_ENTITIES (%i)", num_entities);
00442 
00443     mapent = &entities[num_entities];
00444     num_entities++;
00445 
00446     do {
00447         if (!GetToken(qtrue))
00448             Sys_Error("ParseEntity: EOF without closing brace");
00449         if (*parsedToken == '}') {
00450             break;
00451         } else {
00452             epair_t *e = ParseEpair();
00453             e->next = mapent->epairs;
00454             mapent->epairs = e;
00455         }
00456     } while (1);
00457 
00458     return mapent;
00459 }
00460 
00466 void ParseEntities (void)
00467 {
00468     int subdivide;
00469 
00470     num_entities = 0;
00471     ParseFromMemory(curTile->entdata, curTile->entdatasize);
00472 
00473     while (ParseEntity() != NULL) {
00474     }
00475 
00476     subdivide = atoi(ValueForKey(&entities[0], "subdivide"));
00477     if (subdivide >= 256 && subdivide <= 2048) {
00478         Verb_Printf(VERB_EXTRA, "Using subdivide %d from worldspawn.\n", subdivide);
00479         config.subdivideSize = subdivide;
00480     }
00481 }
00482 
00483 
00488 const char *UnparseEntities (void)
00489 {
00490     char line[2048], key[1024], value[1024];
00491     int i;
00492 
00493     curTile->entdata[0] = '\0';
00494 
00495     for (i = 0; i < num_entities; i++) {
00496         const epair_t *ep = entities[i].epairs;
00497         if (!ep)
00498             continue;   /* ent got removed */
00499 
00500         Q_strcat(curTile->entdata, "{\n", sizeof(curTile->entdata));
00501 
00502         for (ep = entities[i].epairs; ep; ep = ep->next) {
00503             Q_strncpyz(key, ep->key, sizeof(key));
00504             StripTrailingWhitespaces(key);
00505             Q_strncpyz(value, ep->value, sizeof(value));
00506             StripTrailingWhitespaces(value);
00507 
00508             Com_sprintf(line, sizeof(line), "\"%s\" \"%s\"\n", key, value);
00509             Q_strcat(curTile->entdata, line, sizeof(curTile->entdata));
00510         }
00511         Q_strcat(curTile->entdata, "}\n", sizeof(curTile->entdata));
00512     }
00513     curTile->entdatasize = strlen(curTile->entdata);
00514 
00515     return curTile->entdata;
00516 }
00517 
00518 void SetKeyValue (entity_t *ent, const char *key, const char *value)
00519 {
00520     epair_t *ep;
00521 
00522     for (ep = ent->epairs; ep; ep = ep->next)
00523         if (!strcmp(ep->key, key)) {
00524             Mem_Free(ep->value);
00525             ep->value = Mem_StrDup(value);
00526             return;
00527         }
00528     ep = Mem_Alloc(sizeof(*ep));
00529     ep->next = ent->epairs;
00530     ent->epairs = ep;
00531     ep->key = Mem_StrDup(key);
00532     ep->value = Mem_StrDup(value);
00533 }
00534 
00535 const char *ValueForKey (const entity_t *ent, const char *key)
00536 {
00537     const epair_t *ep;
00538 
00539     for (ep = ent->epairs; ep; ep = ep->next)
00540         if (!strcmp(ep->key, key))
00541             return ep->value;
00542     return "";
00543 }
00544 
00545 vec_t FloatForKey (const entity_t *ent, const char *key)
00546 {
00547     const char *k;
00548 
00549     k = ValueForKey(ent, key);
00550     return atof(k);
00551 }
00552 
00556 void GetVectorFromString (const char *value, vec3_t vec)
00557 {
00558     if (value[0] != '\0') {
00559         double v1, v2, v3;
00560 
00561         /* scanf into doubles, then assign, so it is vec_t size independent */
00562         v1 = v2 = v3 = 0;
00563         sscanf(value, "%lf %lf %lf", &v1, &v2, &v3);
00564         vec[0] = v1;
00565         vec[1] = v2;
00566         vec[2] = v3;
00567     } else
00568         VectorClear(vec);
00569 }
00570 
00574 void GetVectorForKey (const entity_t *ent, const char *key, vec3_t vec)
00575 {
00576     const char *k = ValueForKey(ent, key);
00577     GetVectorFromString(k, vec);
00578 }

Generated by  doxygen 1.6.2