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 #include "cmdlib.h"
23 #include "mathlib.h"
24 #include "bspfile.h"
25 #include "scriplib.h"
26 #include "inout.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 */
CompressVis(byte * vis,byte * dest)95 int CompressVis( byte *vis, byte *dest ){
96 int j;
97 int rep;
98 int visrow;
99 byte *dest_p;
100
101 dest_p = dest;
102 // visrow = (r_numvisleafs + 7)>>3;
103 visrow = ( dvis->numclusters + 7 ) >> 3;
104
105 for ( j = 0 ; j < visrow ; j++ )
106 {
107 *dest_p++ = vis[j];
108 if ( vis[j] ) {
109 continue;
110 }
111
112 rep = 1;
113 for ( j++; j < visrow ; j++ )
114 if ( vis[j] || rep == 255 ) {
115 break;
116 }
117 else{
118 rep++;
119 }
120 *dest_p++ = rep;
121 j--;
122 }
123
124 return dest_p - dest;
125 }
126
127
128 /*
129 ===================
130 DecompressVis
131 ===================
132 */
DecompressVis(byte * in,byte * decompressed)133 void DecompressVis( byte *in, byte *decompressed ){
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 *out++ = *in++;
146 continue;
147 }
148
149 c = in[1];
150 if ( !c ) {
151 Error( "DecompressVis: 0 repeat" );
152 }
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 */
SwapBSPFile(qboolean todisk)171 void SwapBSPFile( qboolean todisk ){
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 }
345 else{
346 j = LittleLong( dvis->numclusters );
347 }
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
CopyLump(int lump,void * dest,int size)359 int CopyLump( int lump, void *dest, int size ){
360 int length, ofs;
361
362 length = header->lumps[lump].filelen;
363 ofs = header->lumps[lump].fileofs;
364
365 if ( length % size ) {
366 Error( "LoadBSPFile: odd lump size" );
367 }
368
369 memcpy( dest, (byte *)header + ofs, length );
370
371 return length / size;
372 }
373
374 /*
375 =============
376 LoadBSPFile
377 =============
378 */
LoadBSPFile(char * filename)379 void LoadBSPFile( char *filename ){
380 int i;
381
382 //
383 // load the file header
384 //
385 LoadFile( filename, (void **)&header );
386
387 // swap the header
388 for ( i = 0 ; i < sizeof( dheader_t ) / 4 ; i++ )
389 ( (int *)header )[i] = LittleLong( ( (int *)header )[i] );
390
391 if ( header->ident != IDBSPHEADER ) {
392 Error( "%s is not a IBSP file", filename );
393 }
394 if ( header->version != BSPVERSION ) {
395 Error( "%s is version %i, not %i", filename, header->version, BSPVERSION );
396 }
397
398 nummodels = CopyLump( LUMP_MODELS, dmodels, sizeof( dmodel_t ) );
399 numvertexes = CopyLump( LUMP_VERTEXES, dvertexes, sizeof( dvertex_t ) );
400 numplanes = CopyLump( LUMP_PLANES, dplanes, sizeof( dplane_t ) );
401 numleafs = CopyLump( LUMP_LEAFS, dleafs, sizeof( dleaf_t ) );
402 numnodes = CopyLump( LUMP_NODES, dnodes, sizeof( dnode_t ) );
403 numtexinfo = CopyLump( LUMP_TEXINFO, texinfo, sizeof( texinfo_t ) );
404 numfaces = CopyLump( LUMP_FACES, dfaces, sizeof( dface_t ) );
405 numleaffaces = CopyLump( LUMP_LEAFFACES, dleaffaces, sizeof( dleaffaces[0] ) );
406 numleafbrushes = CopyLump( LUMP_LEAFBRUSHES, dleafbrushes, sizeof( dleafbrushes[0] ) );
407 numsurfedges = CopyLump( LUMP_SURFEDGES, dsurfedges, sizeof( dsurfedges[0] ) );
408 numedges = CopyLump( LUMP_EDGES, dedges, sizeof( dedge_t ) );
409 numbrushes = CopyLump( LUMP_BRUSHES, dbrushes, sizeof( dbrush_t ) );
410 numbrushsides = CopyLump( LUMP_BRUSHSIDES, dbrushsides, sizeof( dbrushside_t ) );
411 numareas = CopyLump( LUMP_AREAS, dareas, sizeof( darea_t ) );
412 numareaportals = CopyLump( LUMP_AREAPORTALS, dareaportals, sizeof( dareaportal_t ) );
413
414 visdatasize = CopyLump( LUMP_VISIBILITY, dvisdata, 1 );
415 lightdatasize = CopyLump( LUMP_LIGHTING, dlightdata, 1 );
416 entdatasize = CopyLump( LUMP_ENTITIES, dentdata, 1 );
417
418 CopyLump( LUMP_POP, dpop, 1 );
419
420 free( header ); // everything has been copied out
421
422 //
423 // swap everything
424 //
425 SwapBSPFile( false );
426 }
427
428
429 /*
430 =============
431 LoadBSPFileTexinfo
432
433 Only loads the texinfo lump, so qdata can scan for textures
434 =============
435 */
LoadBSPFileTexinfo(char * filename)436 void LoadBSPFileTexinfo( char *filename ){
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 }
453 if ( header->version != BSPVERSION ) {
454 Error( "%s is version %i, not %i", filename, header->version, BSPVERSION );
455 }
456
457
458 length = header->lumps[LUMP_TEXINFO].filelen;
459 ofs = header->lumps[LUMP_TEXINFO].fileofs;
460
461 fseek( f, ofs, SEEK_SET );
462 fread( texinfo, length, 1, f );
463 fclose( f );
464
465 numtexinfo = length / sizeof( texinfo_t );
466
467 free( header ); // everything has been copied out
468
469 SwapBSPFile( false );
470 }
471
472
473 //============================================================================
474
475 FILE *wadfile;
476 dheader_t outheader;
477
AddLump(int lumpnum,void * data,int len)478 void AddLump( int lumpnum, void *data, int len ){
479 lump_t *lump;
480
481 lump = &header->lumps[lumpnum];
482
483 lump->fileofs = LittleLong( ftell( wadfile ) );
484 lump->filelen = LittleLong( len );
485 SafeWrite( wadfile, data, ( len + 3 ) & ~3 );
486 }
487
488 /*
489 =============
490 WriteBSPFile
491
492 Swaps the bsp file in place, so it should not be referenced again
493 =============
494 */
WriteBSPFile(char * filename)495 void WriteBSPFile( char *filename ){
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 */
PrintBSPFileSizes(void)542 void PrintBSPFileSizes( void ){
543 if ( !num_entities ) {
544 ParseEntities();
545 }
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
StripTrailing(char * e)587 void StripTrailing( char *e ){
588 char *s;
589
590 s = e + strlen( e ) - 1;
591 while ( s >= e && *s <= 32 )
592 {
593 *s = 0;
594 s--;
595 }
596 }
597
598 /*
599 =================
600 ParseEpair
601 =================
602 */
ParseEpair(void)603 epair_t *ParseEpair( void ){
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 }
612 e->key = copystring( token );
613 GetToken( false );
614 if ( strlen( token ) >= MAX_VALUE - 1 ) {
615 Error( "ParseEpar: token too long" );
616 }
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 */
ParseEntity(void)632 qboolean ParseEntity( void ){
633 epair_t *e;
634 entity_t *mapent;
635
636 if ( !GetToken( true ) ) {
637 return false;
638 }
639
640 if ( strcmp( token, "{" ) ) {
641 Error( "ParseEntity: { not found" );
642 }
643
644 if ( num_entities == MAX_MAP_ENTITIES ) {
645 Error( "num_entities == MAX_MAP_ENTITIES" );
646 }
647
648 mapent = &entities[num_entities];
649 num_entities++;
650
651 do
652 {
653 if ( !GetToken( true ) ) {
654 Error( "ParseEntity: EOF without closing brace" );
655 }
656 if ( !strcmp( token, "}" ) ) {
657 break;
658 }
659 e = ParseEpair();
660 e->next = mapent->epairs;
661 mapent->epairs = e;
662 } while ( 1 );
663
664 return true;
665 }
666
667 /*
668 ================
669 ParseEntities
670
671 Parses the dentdata string into entities
672 ================
673 */
ParseEntities(void)674 void ParseEntities( void ){
675 num_entities = 0;
676 ParseFromMemory( dentdata, entdatasize );
677
678 while ( ParseEntity() )
679 {
680 }
681 }
682
683
684 /*
685 ================
686 UnparseEntities
687
688 Generates the dentdata string from all the entities
689 ================
690 */
UnparseEntities(void)691 void UnparseEntities( void ){
692 char *buf, *end;
693 epair_t *ep;
694 char line[2048];
695 int i;
696 char key[1024], value[1024];
697
698 buf = dentdata;
699 end = buf;
700 *end = 0;
701
702 for ( i = 0 ; i < num_entities ; i++ )
703 {
704 ep = entities[i].epairs;
705 if ( !ep ) {
706 continue; // ent got removed
707
708 }
709 strcat( end,"{\n" );
710 end += 2;
711
712 for ( ep = entities[i].epairs ; ep ; ep = ep->next )
713 {
714 strcpy( key, ep->key );
715 StripTrailing( key );
716 strcpy( value, ep->value );
717 StripTrailing( value );
718
719 sprintf( line, "\"%s\" \"%s\"\n", key, value );
720 strcat( end, line );
721 end += strlen( line );
722 }
723 strcat( end,"}\n" );
724 end += 2;
725
726 if ( end > buf + MAX_MAP_ENTSTRING ) {
727 Error( "Entity text too long" );
728 }
729 }
730 entdatasize = end - buf + 1;
731 }
732
PrintEntity(entity_t * ent)733 void PrintEntity( entity_t *ent ){
734 epair_t *ep;
735
736 printf( "------- entity %p -------\n", ent );
737 for ( ep = ent->epairs ; ep ; ep = ep->next )
738 {
739 printf( "%s = %s\n", ep->key, ep->value );
740 }
741
742 }
743
SetKeyValue(entity_t * ent,char * key,char * value)744 void SetKeyValue( entity_t *ent, char *key, char *value ){
745 epair_t *ep;
746
747 for ( ep = ent->epairs ; ep ; ep = ep->next )
748 if ( !strcmp( ep->key, key ) ) {
749 free( ep->value );
750 ep->value = copystring( value );
751 return;
752 }
753 ep = malloc( sizeof( *ep ) );
754 ep->next = ent->epairs;
755 ent->epairs = ep;
756 ep->key = copystring( key );
757 ep->value = copystring( value );
758 }
759
ValueForKey(entity_t * ent,char * key)760 char *ValueForKey( entity_t *ent, char *key ){
761 epair_t *ep;
762
763 for ( ep = ent->epairs ; ep ; ep = ep->next )
764 if ( !strcmp( ep->key, key ) ) {
765 return ep->value;
766 }
767 return "";
768 }
769
FloatForKey(entity_t * ent,char * key)770 vec_t FloatForKey( entity_t *ent, char *key ){
771 char *k;
772
773 k = ValueForKey( ent, key );
774 return atof( k );
775 }
776
GetVectorForKey(entity_t * ent,char * key,vec3_t vec)777 void GetVectorForKey( entity_t *ent, char *key, vec3_t vec ){
778 char *k;
779 double v1, v2, v3;
780
781 k = ValueForKey( ent, key );
782 // scanf into doubles, then assign, so it is vec_t size independent
783 v1 = v2 = v3 = 0;
784 sscanf( k, "%lf %lf %lf", &v1, &v2, &v3 );
785 vec[0] = v1;
786 vec[1] = v2;
787 vec[2] = v3;
788 }
789