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