]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/extra/common/bspfile.c
Q2Tools source - didn't import this in initially
[xonotic/netradiant.git] / tools / quake2 / extra / common / bspfile.c
1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4
5 This file is part of Quake 2 Tools source code.
6
7 Quake 2 Tools 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 2 Tools 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 Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22
23 #include "cmdlib.h"
24 #include "mathlib.h"
25 #include "bspfile.h"
26 #include "scriplib.h"
27
28 void GetLeafNums (void);
29
30 //=============================================================================
31
32 int                     nummodels;
33 dmodel_t        dmodels[MAX_MAP_MODELS];
34
35 int                     visdatasize;
36 byte            dvisdata[MAX_MAP_VISIBILITY];
37 dvis_t          *dvis = (dvis_t *)dvisdata;
38
39 int                     lightdatasize;
40 byte            dlightdata[MAX_MAP_LIGHTING];
41
42 int                     entdatasize;
43 char            dentdata[MAX_MAP_ENTSTRING];
44
45 int                     numleafs;
46 dleaf_t         dleafs[MAX_MAP_LEAFS];
47
48 int                     numplanes;
49 dplane_t        dplanes[MAX_MAP_PLANES];
50
51 int                     numvertexes;
52 dvertex_t       dvertexes[MAX_MAP_VERTS];
53
54 int                     numnodes;
55 dnode_t         dnodes[MAX_MAP_NODES];
56
57 int                     numtexinfo;
58 texinfo_t       texinfo[MAX_MAP_TEXINFO];
59
60 int                     numfaces;
61 dface_t         dfaces[MAX_MAP_FACES];
62
63 int                     numedges;
64 dedge_t         dedges[MAX_MAP_EDGES];
65
66 int                     numleaffaces;
67 unsigned short          dleaffaces[MAX_MAP_LEAFFACES];
68
69 int                     numleafbrushes;
70 unsigned short          dleafbrushes[MAX_MAP_LEAFBRUSHES];
71
72 int                     numsurfedges;
73 int                     dsurfedges[MAX_MAP_SURFEDGES];
74
75 int                     numbrushes;
76 dbrush_t        dbrushes[MAX_MAP_BRUSHES];
77
78 int                     numbrushsides;
79 dbrushside_t    dbrushsides[MAX_MAP_BRUSHSIDES];
80
81 int                     numareas;
82 darea_t         dareas[MAX_MAP_AREAS];
83
84 int                     numareaportals;
85 dareaportal_t   dareaportals[MAX_MAP_AREAPORTALS];
86
87 byte            dpop[256];
88
89 /*
90 ===============
91 CompressVis
92
93 ===============
94 */
95 int CompressVis (byte *vis, byte *dest)
96 {
97         int             j;
98         int             rep;
99         int             visrow;
100         byte    *dest_p;
101
102         dest_p = dest;
103 //      visrow = (r_numvisleafs + 7)>>3;
104         visrow = (dvis->numclusters + 7)>>3;
105
106         for (j=0 ; j<visrow ; j++)
107         {
108                 *dest_p++ = vis[j];
109                 if (vis[j])
110                         continue;
111
112                 rep = 1;
113                 for ( j++; j<visrow ; j++)
114                         if (vis[j] || rep == 255)
115                                 break;
116                         else
117                                 rep++;
118                 *dest_p++ = rep;
119                 j--;
120         }
121
122         return dest_p - dest;
123 }
124
125
126 /*
127 ===================
128 DecompressVis
129 ===================
130 */
131 void DecompressVis (byte *in, byte *decompressed)
132 {
133         int             c;
134         byte    *out;
135         int             row;
136
137 //      row = (r_numvisleafs+7)>>3;
138         row = (dvis->numclusters+7)>>3;
139         out = decompressed;
140
141         do
142         {
143                 if (*in)
144                 {
145                         *out++ = *in++;
146                         continue;
147                 }
148
149                 c = in[1];
150                 if (!c)
151                         Error ("DecompressVis: 0 repeat");
152                 in += 2;
153                 while (c)
154                 {
155                         *out++ = 0;
156                         c--;
157                 }
158         } while (out - decompressed < row);
159 }
160
161 //=============================================================================
162
163 /*
164 =============
165 SwapBSPFile
166
167 Byte swaps all data in a bsp file.
168 =============
169 */
170 void SwapBSPFile (qboolean todisk)
171 {
172         int                             i, j;
173         dmodel_t                *d;
174
175
176 // models
177         for (i=0 ; i<nummodels ; i++)
178         {
179                 d = &dmodels[i];
180
181                 d->firstface = LittleLong (d->firstface);
182                 d->numfaces = LittleLong (d->numfaces);
183                 d->headnode = LittleLong (d->headnode);
184
185                 for (j=0 ; j<3 ; j++)
186                 {
187                         d->mins[j] = LittleFloat(d->mins[j]);
188                         d->maxs[j] = LittleFloat(d->maxs[j]);
189                         d->origin[j] = LittleFloat(d->origin[j]);
190                 }
191         }
192
193 //
194 // vertexes
195 //
196         for (i=0 ; i<numvertexes ; i++)
197         {
198                 for (j=0 ; j<3 ; j++)
199                         dvertexes[i].point[j] = LittleFloat (dvertexes[i].point[j]);
200         }
201
202 //
203 // planes
204 //
205         for (i=0 ; i<numplanes ; i++)
206         {
207                 for (j=0 ; j<3 ; j++)
208                         dplanes[i].normal[j] = LittleFloat (dplanes[i].normal[j]);
209                 dplanes[i].dist = LittleFloat (dplanes[i].dist);
210                 dplanes[i].type = LittleLong (dplanes[i].type);
211         }
212
213 //
214 // texinfos
215 //
216         for (i=0 ; i<numtexinfo ; i++)
217         {
218                 for (j=0 ; j<8 ; j++)
219                         texinfo[i].vecs[0][j] = LittleFloat (texinfo[i].vecs[0][j]);
220                 texinfo[i].flags = LittleLong (texinfo[i].flags);
221                 texinfo[i].value = LittleLong (texinfo[i].value);
222                 texinfo[i].nexttexinfo = LittleLong (texinfo[i].nexttexinfo);
223         }
224
225 //
226 // faces
227 //
228         for (i=0 ; i<numfaces ; i++)
229         {
230                 dfaces[i].texinfo = LittleShort (dfaces[i].texinfo);
231                 dfaces[i].planenum = LittleShort (dfaces[i].planenum);
232                 dfaces[i].side = LittleShort (dfaces[i].side);
233                 dfaces[i].lightofs = LittleLong (dfaces[i].lightofs);
234                 dfaces[i].firstedge = LittleLong (dfaces[i].firstedge);
235                 dfaces[i].numedges = LittleShort (dfaces[i].numedges);
236         }
237
238 //
239 // nodes
240 //
241         for (i=0 ; i<numnodes ; i++)
242         {
243                 dnodes[i].planenum = LittleLong (dnodes[i].planenum);
244                 for (j=0 ; j<3 ; j++)
245                 {
246                         dnodes[i].mins[j] = LittleShort (dnodes[i].mins[j]);
247                         dnodes[i].maxs[j] = LittleShort (dnodes[i].maxs[j]);
248                 }
249                 dnodes[i].children[0] = LittleLong (dnodes[i].children[0]);
250                 dnodes[i].children[1] = LittleLong (dnodes[i].children[1]);
251                 dnodes[i].firstface = LittleShort (dnodes[i].firstface);
252                 dnodes[i].numfaces = LittleShort (dnodes[i].numfaces);
253         }
254
255 //
256 // leafs
257 //
258         for (i=0 ; i<numleafs ; i++)
259         {
260                 dleafs[i].contents = LittleLong (dleafs[i].contents);
261                 dleafs[i].cluster = LittleShort (dleafs[i].cluster);
262                 dleafs[i].area = LittleShort (dleafs[i].area);
263                 for (j=0 ; j<3 ; j++)
264                 {
265                         dleafs[i].mins[j] = LittleShort (dleafs[i].mins[j]);
266                         dleafs[i].maxs[j] = LittleShort (dleafs[i].maxs[j]);
267                 }
268
269                 dleafs[i].firstleafface = LittleShort (dleafs[i].firstleafface);
270                 dleafs[i].numleaffaces = LittleShort (dleafs[i].numleaffaces);
271                 dleafs[i].firstleafbrush = LittleShort (dleafs[i].firstleafbrush);
272                 dleafs[i].numleafbrushes = LittleShort (dleafs[i].numleafbrushes);
273         }
274
275 //
276 // leaffaces
277 //
278         for (i=0 ; i<numleaffaces ; i++)
279                 dleaffaces[i] = LittleShort (dleaffaces[i]);
280
281 //
282 // leafbrushes
283 //
284         for (i=0 ; i<numleafbrushes ; i++)
285                 dleafbrushes[i] = LittleShort (dleafbrushes[i]);
286
287 //
288 // surfedges
289 //
290         for (i=0 ; i<numsurfedges ; i++)
291                 dsurfedges[i] = LittleLong (dsurfedges[i]);
292
293 //
294 // edges
295 //
296         for (i=0 ; i<numedges ; i++)
297         {
298                 dedges[i].v[0] = LittleShort (dedges[i].v[0]);
299                 dedges[i].v[1] = LittleShort (dedges[i].v[1]);
300         }
301
302 //
303 // brushes
304 //
305         for (i=0 ; i<numbrushes ; i++)
306         {
307                 dbrushes[i].firstside = LittleLong (dbrushes[i].firstside);
308                 dbrushes[i].numsides = LittleLong (dbrushes[i].numsides);
309                 dbrushes[i].contents = LittleLong (dbrushes[i].contents);
310         }
311
312 //
313 // areas
314 //
315         for (i=0 ; i<numareas ; i++)
316         {
317                 dareas[i].numareaportals = LittleLong (dareas[i].numareaportals);
318                 dareas[i].firstareaportal = LittleLong (dareas[i].firstareaportal);
319         }
320
321 //
322 // areasportals
323 //
324         for (i=0 ; i<numareaportals ; i++)
325         {
326                 dareaportals[i].portalnum = LittleLong (dareaportals[i].portalnum);
327                 dareaportals[i].otherarea = LittleLong (dareaportals[i].otherarea);
328         }
329
330 //
331 // brushsides
332 //
333         for (i=0 ; i<numbrushsides ; i++)
334         {
335                 dbrushsides[i].planenum = LittleShort (dbrushsides[i].planenum);
336                 dbrushsides[i].texinfo = LittleShort (dbrushsides[i].texinfo);
337         }
338
339 //
340 // visibility
341 //
342         if (todisk)
343                 j = dvis->numclusters;
344         else
345                 j = LittleLong(dvis->numclusters);
346         dvis->numclusters = LittleLong (dvis->numclusters);
347         for (i=0 ; i<j ; i++)
348         {
349                 dvis->bitofs[i][0] = LittleLong (dvis->bitofs[i][0]);
350                 dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]);
351         }
352 }
353
354
355 dheader_t       *header;
356
357 int CopyLump (int lump, void *dest, int size)
358 {
359         int             length, ofs;
360
361         length = header->lumps[lump].filelen;
362         ofs = header->lumps[lump].fileofs;
363
364         if (length % size)
365                 Error ("LoadBSPFile: odd lump size");
366
367         memcpy (dest, (byte *)header + ofs, length);
368
369         return length / size;
370 }
371
372 /*
373 =============
374 LoadBSPFile
375 =============
376 */
377 void    LoadBSPFile (char *filename)
378 {
379         int                     i;
380
381 //
382 // load the file header
383 //
384         LoadFile (filename, (void **)&header);
385
386 // swap the header
387         for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
388                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
389
390         if (header->ident != IDBSPHEADER)
391                 Error ("%s is not a IBSP file", filename);
392         if (header->version != BSPVERSION)
393                 Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
394
395         nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t));
396         numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t));
397         numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t));
398         numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t));
399         numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t));
400         numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t));
401         numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t));
402         numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0]));
403         numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0]));
404         numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0]));
405         numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t));
406         numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t));
407         numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t));
408         numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t));
409         numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t));
410
411         visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1);
412         lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1);
413         entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1);
414
415         CopyLump (LUMP_POP, dpop, 1);
416
417         free (header);          // everything has been copied out
418
419 //
420 // swap everything
421 //
422         SwapBSPFile (false);
423 }
424
425
426 /*
427 =============
428 LoadBSPFileTexinfo
429
430 Only loads the texinfo lump, so qdata can scan for textures
431 =============
432 */
433 void    LoadBSPFileTexinfo (char *filename)
434 {
435         int                     i;
436         FILE            *f;
437         int             length, ofs;
438
439         header = malloc(sizeof(dheader_t));
440
441         f = fopen (filename, "rb");
442         fread (header, sizeof(dheader_t), 1, f);
443
444 // swap the header
445         for (i=0 ; i< sizeof(dheader_t)/4 ; i++)
446                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
447
448         if (header->ident != IDBSPHEADER)
449                 Error ("%s is not a IBSP file", filename);
450         if (header->version != BSPVERSION)
451                 Error ("%s is version %i, not %i", filename, header->version, BSPVERSION);
452
453
454         length = header->lumps[LUMP_TEXINFO].filelen;
455         ofs = header->lumps[LUMP_TEXINFO].fileofs;
456
457         fseek (f, ofs, SEEK_SET);
458         fread (texinfo, length, 1, f);
459         fclose (f);
460
461         numtexinfo = length / sizeof(texinfo_t);
462
463         free (header);          // everything has been copied out
464
465         SwapBSPFile (false);
466 }
467
468
469 //============================================================================
470
471 FILE            *wadfile;
472 dheader_t       outheader;
473
474 void AddLump (int lumpnum, void *data, int len)
475 {
476         lump_t *lump;
477
478         lump = &header->lumps[lumpnum];
479
480         lump->fileofs = LittleLong( ftell(wadfile) );
481         lump->filelen = LittleLong(len);
482         SafeWrite (wadfile, data, (len+3)&~3);
483 }
484
485 /*
486 =============
487 WriteBSPFile
488
489 Swaps the bsp file in place, so it should not be referenced again
490 =============
491 */
492 void    WriteBSPFile (char *filename)
493 {
494         header = &outheader;
495         memset (header, 0, sizeof(dheader_t));
496
497         SwapBSPFile (true);
498
499         header->ident = LittleLong (IDBSPHEADER);
500         header->version = LittleLong (BSPVERSION);
501
502         wadfile = SafeOpenWrite (filename);
503         SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later
504
505         AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t));
506         AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t));
507         AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t));
508         AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t));
509         AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t));
510         AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t));
511         AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t));
512         AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t));
513         AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0]));
514         AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0]));
515         AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0]));
516         AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t));
517         AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t));
518         AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t));
519         AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t));
520
521         AddLump (LUMP_LIGHTING, dlightdata, lightdatasize);
522         AddLump (LUMP_VISIBILITY, dvisdata, visdatasize);
523         AddLump (LUMP_ENTITIES, dentdata, entdatasize);
524         AddLump (LUMP_POP, dpop, sizeof(dpop));
525
526         fseek (wadfile, 0, SEEK_SET);
527         SafeWrite (wadfile, header, sizeof(dheader_t));
528         fclose (wadfile);
529 }
530
531 //============================================================================
532
533 /*
534 =============
535 PrintBSPFileSizes
536
537 Dumps info about current file
538 =============
539 */
540 void PrintBSPFileSizes (void)
541 {
542         if (!num_entities)
543                 ParseEntities ();
544
545         printf ("%5i models       %7i\n"
546                 ,nummodels, (int)(nummodels*sizeof(dmodel_t)));
547         printf ("%5i brushes      %7i\n"
548                 ,numbrushes, (int)(numbrushes*sizeof(dbrush_t)));
549         printf ("%5i brushsides   %7i\n"
550                 ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t)));
551         printf ("%5i planes       %7i\n"
552                 ,numplanes, (int)(numplanes*sizeof(dplane_t)));
553         printf ("%5i texinfo      %7i\n"
554                 ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t)));
555         printf ("%5i entdata      %7i\n", num_entities, entdatasize);
556
557         printf ("\n");
558
559         printf ("%5i vertexes     %7i\n"
560                 ,numvertexes, (int)(numvertexes*sizeof(dvertex_t)));
561         printf ("%5i nodes        %7i\n"
562                 ,numnodes, (int)(numnodes*sizeof(dnode_t)));
563         printf ("%5i faces        %7i\n"
564                 ,numfaces, (int)(numfaces*sizeof(dface_t)));
565         printf ("%5i leafs        %7i\n"
566                 ,numleafs, (int)(numleafs*sizeof(dleaf_t)));
567         printf ("%5i leaffaces    %7i\n"
568                 ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0])));
569         printf ("%5i leafbrushes  %7i\n"
570                 ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0])));
571         printf ("%5i surfedges    %7i\n"
572                 ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0])));
573         printf ("%5i edges        %7i\n"
574                 ,numedges, (int)(numedges*sizeof(dedge_t)));
575         printf ("      lightdata    %7i\n", lightdatasize);
576         printf ("      visdata      %7i\n", visdatasize);
577 }
578
579
580 //============================================
581
582 int                     num_entities;
583 entity_t        entities[MAX_MAP_ENTITIES];
584
585 void StripTrailing (char *e)
586 {
587         char    *s;
588
589         s = e + strlen(e)-1;
590         while (s >= e && *s <= 32)
591         {
592                 *s = 0;
593                 s--;
594         }
595 }
596
597 /*
598 =================
599 ParseEpair
600 =================
601 */
602 epair_t *ParseEpair (void)
603 {
604         epair_t *e;
605
606         e = malloc (sizeof(epair_t));
607         memset (e, 0, sizeof(epair_t));
608
609         if (strlen(token) >= MAX_KEY-1)
610                 Error ("ParseEpar: token too long");
611         e->key = copystring(token);
612         GetToken (false);
613         if (strlen(token) >= MAX_VALUE-1)
614                 Error ("ParseEpar: token too long");
615         e->value = copystring(token);
616
617         // strip trailing spaces
618         StripTrailing (e->key);
619         StripTrailing (e->value);
620
621         return e;
622 }
623
624
625 /*
626 ================
627 ParseEntity
628 ================
629 */
630 qboolean        ParseEntity (void)
631 {
632         epair_t         *e;
633         entity_t        *mapent;
634
635         if (!GetToken (true))
636                 return false;
637
638         if (strcmp (token, "{") )
639                 Error ("ParseEntity: { not found");
640
641         if (num_entities == MAX_MAP_ENTITIES)
642                 Error ("num_entities == MAX_MAP_ENTITIES");
643
644         mapent = &entities[num_entities];
645         num_entities++;
646
647         do
648         {
649                 if (!GetToken (true))
650                         Error ("ParseEntity: EOF without closing brace");
651                 if (!strcmp (token, "}") )
652                         break;
653                 e = ParseEpair ();
654                 e->next = mapent->epairs;
655                 mapent->epairs = e;
656         } while (1);
657
658         return true;
659 }
660
661 /*
662 ================
663 ParseEntities
664
665 Parses the dentdata string into entities
666 ================
667 */
668 void ParseEntities (void)
669 {
670         num_entities = 0;
671         ParseFromMemory (dentdata, entdatasize);
672
673         while (ParseEntity ())
674         {
675         }
676 }
677
678
679 /*
680 ================
681 UnparseEntities
682
683 Generates the dentdata string from all the entities
684 ================
685 */
686 void UnparseEntities (void)
687 {
688         char    *buf, *end;
689         epair_t *ep;
690         char    line[2048];
691         int             i;
692         char    key[1024], value[1024];
693
694         buf = dentdata;
695         end = buf;
696         *end = 0;
697
698         for (i=0 ; i<num_entities ; i++)
699         {
700                 ep = entities[i].epairs;
701                 if (!ep)
702                         continue;       // ent got removed
703
704                 strcat (end,"{\n");
705                 end += 2;
706
707                 for (ep = entities[i].epairs ; ep ; ep=ep->next)
708                 {
709                         strcpy (key, ep->key);
710                         StripTrailing (key);
711                         strcpy (value, ep->value);
712                         StripTrailing (value);
713
714                         sprintf (line, "\"%s\" \"%s\"\n", key, value);
715                         strcat (end, line);
716                         end += strlen(line);
717                 }
718                 strcat (end,"}\n");
719                 end += 2;
720
721                 if (end > buf + MAX_MAP_ENTSTRING)
722                         Error ("Entity text too long");
723         }
724         entdatasize = end - buf + 1;
725 }
726
727 void PrintEntity (entity_t *ent)
728 {
729         epair_t *ep;
730
731         printf ("------- entity %p -------\n", ent);
732         for (ep=ent->epairs ; ep ; ep=ep->next)
733         {
734                 printf ("%s = %s\n", ep->key, ep->value);
735         }
736
737 }
738
739 void    SetKeyValue (entity_t *ent, char *key, char *value)
740 {
741         epair_t *ep;
742
743         for (ep=ent->epairs ; ep ; ep=ep->next)
744                 if (!strcmp (ep->key, key) )
745                 {
746                         free (ep->value);
747                         ep->value = copystring(value);
748                         return;
749                 }
750         ep = malloc (sizeof(*ep));
751         ep->next = ent->epairs;
752         ent->epairs = ep;
753         ep->key = copystring(key);
754         ep->value = copystring(value);
755 }
756
757 char    *ValueForKey (entity_t *ent, char *key)
758 {
759         epair_t *ep;
760
761         for (ep=ent->epairs ; ep ; ep=ep->next)
762                 if (!strcmp (ep->key, key) )
763                         return ep->value;
764         return "";
765 }
766
767 vec_t   FloatForKey (entity_t *ent, char *key)
768 {
769         char    *k;
770
771         k = ValueForKey (ent, key);
772         return atof(k);
773 }
774
775 void    GetVectorForKey (entity_t *ent, char *key, vec3_t vec)
776 {
777         char    *k;
778         double  v1, v2, v3;
779
780         k = ValueForKey (ent, key);
781 // scanf into doubles, then assign, so it is vec_t size independent
782         v1 = v2 = v3 = 0;
783         sscanf (k, "%lf %lf %lf", &v1, &v2, &v3);
784         vec[0] = v1;
785         vec[1] = v2;
786         vec[2] = v3;
787 }
788
789