Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Demos / BspDemo / BspLoader.cpp
1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU bteral 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 III Arena 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 bteral Public License for more details.
16
17 You should have received a copy of the GNU bteral Public License
18 along with Foobar; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22
23
24 #include "BspLoader.h"
25 #include <stdio.h>
26 #include <string.h>
27
28 typedef struct
29 {
30         char    filename[1024];
31         char    *buffer,*script_p,*end_p;
32         int     line;
33 } BSPScript;
34
35 #define MAX_INCLUDES    8
36 BSPScript       scriptstack[MAX_INCLUDES];
37 BSPScript       *script;
38 int                     scriptline;
39
40 char    token[BSPMAXTOKEN];
41 bool endofscript;
42 bool tokenready;                     // only true if UnGetToken was just called
43
44 //
45 //loadBSPFile
46 //
47
48 int extrasize = 100;
49
50 BspLoader::BspLoader()
51         :m_num_entities(0)
52 {
53         m_Endianness = getMachineEndianness();
54         if (m_Endianness == BSP_BIG_ENDIAN)
55         {
56                 printf("Machine is BIG_ENDIAN\n");
57         } else
58         {
59                 printf("Machine is Little Endian\n");
60         }
61 }
62
63
64 bool    BspLoader::loadBSPFile( void* memoryBuffer) {
65         
66         BSPHeader       *header = (BSPHeader*) memoryBuffer;
67
68         // load the file header
69         if (header)
70         {
71                 // swap the header
72                 swapBlock( (int *)header, sizeof(*header) );
73                 
74                 int length = (header->lumps[BSPLUMP_SHADERS].filelen) / sizeof(BSPShader);
75                 m_dshaders.resize(length+extrasize);
76                 m_numShaders = copyLump( header, BSPLUMP_SHADERS, &m_dshaders[0], sizeof(BSPShader) );
77
78                 length = (header->lumps[LUMP_MODELS].filelen) / sizeof(BSPModel);
79                 m_dmodels.resize(length+extrasize);
80                 m_nummodels = copyLump( header, LUMP_MODELS, &m_dmodels[0], sizeof(BSPModel) );
81
82                 length = (header->lumps[BSPLUMP_PLANES].filelen) / sizeof(BSPPlane);
83                 m_dplanes.resize(length+extrasize);
84                 m_numplanes = copyLump( header, BSPLUMP_PLANES, &m_dplanes[0], sizeof(BSPPlane) );
85
86                 length = (header->lumps[BSPLUMP_LEAFS].filelen) / sizeof(BSPLeaf);
87                 m_dleafs.resize(length+extrasize);
88                 m_numleafs = copyLump( header, BSPLUMP_LEAFS, &m_dleafs[0], sizeof(BSPLeaf) );
89
90                 length = (header->lumps[BSPLUMP_NODES].filelen) / sizeof(BSPNode);
91                 m_dnodes.resize(length+extrasize);
92                 m_numnodes = copyLump( header, BSPLUMP_NODES, &m_dnodes[0], sizeof(BSPNode) );
93
94                 length = (header->lumps[BSPLUMP_LEAFSURFACES].filelen) / sizeof(m_dleafsurfaces[0]);
95                 m_dleafsurfaces.resize(length+extrasize);
96                 m_numleafsurfaces = copyLump( header, BSPLUMP_LEAFSURFACES, &m_dleafsurfaces[0], sizeof(m_dleafsurfaces[0]) );
97
98                 length = (header->lumps[BSPLUMP_LEAFBRUSHES].filelen) / sizeof(m_dleafbrushes[0]) ;
99                 m_dleafbrushes.resize(length+extrasize);
100                 m_numleafbrushes = copyLump( header, BSPLUMP_LEAFBRUSHES, &m_dleafbrushes[0], sizeof(m_dleafbrushes[0]) );
101
102                 length = (header->lumps[LUMP_BRUSHES].filelen) / sizeof(BSPBrush);
103                 m_dbrushes.resize(length+extrasize);
104                 m_numbrushes = copyLump( header, LUMP_BRUSHES, &m_dbrushes[0], sizeof(BSPBrush) );
105
106
107                 length = (header->lumps[LUMP_BRUSHSIDES].filelen) / sizeof(BSPBrushSide);
108                 m_dbrushsides.resize(length+extrasize);
109                 m_numbrushsides = copyLump( header, LUMP_BRUSHSIDES, &m_dbrushsides[0], sizeof(BSPBrushSide) );
110
111                 
112                 length = (header->lumps[LUMP_SURFACES].filelen) / sizeof(BSPSurface);
113                 m_drawSurfaces.resize(length+extrasize);
114                 m_numDrawSurfaces = copyLump( header, LUMP_SURFACES, &m_drawSurfaces[0], sizeof(BSPSurface) );
115
116
117                 length = (header->lumps[LUMP_DRAWINDEXES].filelen) / sizeof(m_drawIndexes[0]);
118                 m_drawIndexes.resize(length+extrasize);
119                 m_numDrawIndexes = copyLump( header, LUMP_DRAWINDEXES, &m_drawIndexes[0], sizeof(m_drawIndexes[0]) );
120
121                 length = (header->lumps[LUMP_VISIBILITY].filelen) / 1;
122                 m_visBytes.resize(length+extrasize);
123                 m_numVisBytes = copyLump( header, LUMP_VISIBILITY, &m_visBytes[0], 1 );
124
125                 length = (header->lumps[LUMP_LIGHTMAPS].filelen) / 1;
126                 m_lightBytes.resize(length+extrasize);
127                 m_numLightBytes = copyLump( header, LUMP_LIGHTMAPS, &m_lightBytes[0], 1 );
128
129                 length = (header->lumps[BSPLUMP_ENTITIES].filelen) / 1;
130                 m_dentdata.resize(length+extrasize);
131                 m_entdatasize = copyLump( header, BSPLUMP_ENTITIES, &m_dentdata[0], 1);
132
133                 length = (header->lumps[LUMP_LIGHTGRID].filelen) / 1;
134                 m_gridData.resize(length+extrasize);
135                 m_numGridPoints = copyLump( header, LUMP_LIGHTGRID, &m_gridData[0], 8 );
136
137                 // swap everything
138                 swapBSPFile();
139
140                 return true;
141
142         }
143         return false;
144 }
145
146
147
148 const char* BspLoader::getValueForKey( const  BSPEntity* ent, const char* key ) const {
149
150         const BSPKeyValuePair* ep;
151         
152         for (ep=ent->epairs ; ep ; ep=ep->next) {
153                 if (!strcmp(ep->key, key) ) {
154                         return ep->value;
155                 }
156         }
157         return "";
158 }
159
160 float   BspLoader::getFloatForKey( const BSPEntity *ent, const char *key ) {
161         const char      *k;
162         
163         k = getValueForKey( ent, key );
164         return float(atof(k));
165 }
166
167 bool    BspLoader::getVectorForKey( const BSPEntity *ent, const char *key, BSPVector3 vec ) {
168
169         const char      *k;
170         k = getValueForKey (ent, key);
171         if (strcmp(k, ""))
172         {
173                 sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
174                 return true;
175         }
176         return false;
177 }
178
179
180
181
182 /*
183 ==============
184 parseFromMemory
185 ==============
186 */
187 void BspLoader::parseFromMemory (char *buffer, int size)
188 {
189         script = scriptstack;
190         script++;
191         if (script == &scriptstack[MAX_INCLUDES])
192         {
193                 //printf("script file exceeded MAX_INCLUDES");
194         }
195         strcpy (script->filename, "memory buffer" );
196
197         script->buffer = buffer;
198         script->line = 1;
199         script->script_p = script->buffer;
200         script->end_p = script->buffer + size;
201
202         endofscript = false;
203         tokenready = false;
204 }
205
206
207 bool BspLoader::isEndOfScript (bool crossline)
208 {
209         if (!crossline)
210                 //printf("Line %i is incomplete\n",scriptline);
211
212         if (!strcmp (script->filename, "memory buffer"))
213         {
214                 endofscript = true;
215                 return false;
216         }
217
218         //free (script->buffer);
219         if (script == scriptstack+1)
220         {
221                 endofscript = true;
222                 return false;
223         }
224         script--;
225         scriptline = script->line;
226         //printf ("returning to %s\n", script->filename);
227         return getToken (crossline);
228 }
229
230 /*
231
232 ==============
233 getToken
234 ==============
235 */
236 bool BspLoader::getToken (bool crossline)
237 {
238         char    *token_p;
239
240         if (tokenready)                         // is a token allready waiting?
241         {
242                 tokenready = false;
243                 return true;
244         }
245
246         if (script->script_p >= script->end_p)
247                 return isEndOfScript (crossline);
248
249 //
250 // skip space
251 //
252 skipspace:
253         while (*script->script_p <= 32)
254         {
255                 if (script->script_p >= script->end_p)
256                         return isEndOfScript (crossline);
257                 if (*script->script_p++ == '\n')
258                 {
259                         if (!crossline)
260                         {
261                                 //printf("Line %i is incomplete\n",scriptline);
262                         }
263                         scriptline = script->line++;
264                 }
265         }
266
267         if (script->script_p >= script->end_p)
268                 return isEndOfScript (crossline);
269
270         // ; # // comments
271         if (*script->script_p == ';' || *script->script_p == '#'
272                 || ( script->script_p[0] == '/' && script->script_p[1] == '/') )
273         {
274                 if (!crossline)
275                 {
276                         //printf("Line %i is incomplete\n",scriptline);
277                 }
278                 while (*script->script_p++ != '\n')
279                         if (script->script_p >= script->end_p)
280                                 return isEndOfScript (crossline);
281                 scriptline = script->line++;
282                 goto skipspace;
283         }
284
285         // /* */ comments
286         if (script->script_p[0] == '/' && script->script_p[1] == '*')
287         {
288                 if (!crossline)
289                 {
290                         //printf("Line %i is incomplete\n",scriptline);
291                 }
292                 script->script_p+=2;
293                 while (script->script_p[0] != '*' && script->script_p[1] != '/')
294                 {
295                         if ( *script->script_p == '\n' ) {
296                                 scriptline = script->line++;
297                         }
298                         script->script_p++;
299                         if (script->script_p >= script->end_p)
300                                 return isEndOfScript (crossline);
301                 }
302                 script->script_p += 2;
303                 goto skipspace;
304         }
305
306 //
307 // copy token
308 //
309         token_p = token;
310
311         if (*script->script_p == '"')
312         {
313                 // quoted token
314                 script->script_p++;
315                 while (*script->script_p != '"')
316                 {
317                         *token_p++ = *script->script_p++;
318                         if (script->script_p == script->end_p)
319                                 break;
320                         if (token_p == &token[BSPMAXTOKEN])
321                         {
322                                 //printf ("Token too large on line %i\n",scriptline);
323                         }
324                 }
325                 script->script_p++;
326         }
327         else    // regular token
328         while ( *script->script_p > 32 && *script->script_p != ';')
329         {
330                 *token_p++ = *script->script_p++;
331                 if (script->script_p == script->end_p)
332                         break;
333                 if (token_p == &token[BSPMAXTOKEN])
334                 {
335                         //printf ("Token too large on line %i\n",scriptline);
336                 }
337         }
338
339         *token_p = 0;
340
341         if (!strcmp (token, "$include"))
342         {
343                 //getToken (false);
344                 //AddScriptToStack (token);
345                 return false;//getToken (crossline);
346         }
347
348         return true;
349 }
350
351 char *BspLoader::copystring(const char *s)
352 {
353         char    *b;
354         b = (char*) malloc( strlen(s)+1);
355         strcpy (b, s);
356         return b;
357 }
358
359 void BspLoader::stripTrailing( char *e ) {
360         char    *s;
361
362         s = e + strlen(e)-1;
363         while (s >= e && *s <= 32)
364         {
365                 *s = 0;
366                 s--;
367         }
368 }
369 /*
370 =================
371 parseEpair
372 =================
373 */
374 BSPKeyValuePair *BspLoader::parseEpair( void ) {
375         BSPKeyValuePair *e;
376
377         e = (struct BSPPair*) malloc( sizeof(BSPKeyValuePair));
378         memset( e, 0, sizeof(BSPKeyValuePair) );
379         
380         if ( strlen(token) >= BSPMAX_KEY-1 ) {
381                 //printf ("ParseEpar: token too long");
382         }
383         e->key = copystring( token );
384         getToken( false );
385         if ( strlen(token) >= BSPMAX_VALUE-1 ) {
386
387                 //printf ("ParseEpar: token too long");
388         }
389         e->value = copystring( token );
390
391         // strip trailing spaces that sometimes get accidentally
392         // added in the editor
393         stripTrailing( e->key );
394         stripTrailing( e->value );
395
396         return e;
397 }
398
399
400 /*
401 ================
402 parseEntity
403 ================
404 */
405 bool    BspLoader::parseEntity( void ) {
406         BSPKeyValuePair         *e;
407         BSPEntity       *mapent;
408
409         if ( !getToken (true) ) {
410                 return false;
411         }
412
413         if ( strcmp (token, "{") ) {
414
415                 //printf ("parseEntity: { not found");
416         }
417
418         BSPEntity bla;
419         bla.brushes = 0;
420         bla.epairs = 0;
421         bla.firstDrawSurf = 0;
422         bla.origin[0] = 0.f;
423         bla.origin[1] = 0.f;
424         bla.origin[2] = 0.f;
425         bla.patches = 0;
426
427         m_entities.push_back(bla);
428         mapent = &m_entities[m_entities.size()-1];
429         m_num_entities++;
430
431         do {
432                 if ( !getToken (true) ) {
433                         //printf("parseEntity: EOF without closing brace");
434                 }
435                 if ( !strcmp (token, "}") ) {
436                         break;
437                 }
438                 e = (struct BSPPair*)parseEpair ();
439                 e->next = mapent->epairs;
440                 mapent->epairs = e;
441         } while (1);
442         
443         return true;
444 }
445
446 /*
447 ================
448 parseEntities
449
450 Parses the dentdata string into entities
451 ================
452 */
453 void BspLoader::parseEntities( void ) {
454         m_num_entities = 0;
455         m_entities.clear();
456
457         parseFromMemory( &m_dentdata[0], m_entdatasize );
458
459         while ( parseEntity () ) {
460         }       
461 }
462
463
464
465 int BspLoader::getMachineEndianness()
466 {
467    long int i = 1;
468    const char *p = (const char *) &i;
469    if (p[0] == 1)  // Lowest address contains the least significant byte
470            return BSP_LITTLE_ENDIAN;
471    else
472            return BSP_BIG_ENDIAN;
473 }
474
475 short   BspLoader::isLittleShort (short l)
476 {
477         if (machineEndianness() == BSP_BIG_ENDIAN)
478         {
479                 unsigned char    b1,b2;
480
481                 b1 = l&255;
482                 b2 = (l>>8)&255;
483
484                 return (b1<<8) + b2;
485         }
486         //little endian
487         return l;
488 }
489
490 short   BspLoader::isBigShort (short l)
491 {
492         if (machineEndianness() == BSP_BIG_ENDIAN)
493         {
494                 return l;
495         }
496
497         unsigned char   b1,b2;
498
499         b1 = l&255;
500         b2 = (l>>8)&255;
501
502         return (b1<<8) + b2;
503
504
505
506 }
507
508
509 int    BspLoader::isLittleLong (int l)
510 {
511         if (machineEndianness() == BSP_BIG_ENDIAN)
512         {
513                 unsigned char    b1,b2,b3,b4;
514
515                 b1 = l&255;
516                 b2 = (l>>8)&255;
517                 b3 = (l>>16)&255;
518                 b4 = (l>>24)&255;
519
520                 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
521         }
522
523         //little endian
524         return l;
525
526 }
527
528 int    BspLoader::isBigLong (int l)
529 {
530         if (machineEndianness() == BSP_BIG_ENDIAN)
531         {
532                 return l;
533         }
534
535
536         unsigned char    b1,b2,b3,b4;
537
538         b1 = l&255;
539         b2 = (l>>8)&255;
540         b3 = (l>>16)&255;
541         b4 = (l>>24)&255;
542
543         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
544
545 }
546
547
548 float   BspLoader::isLittleFloat (float l)
549 {
550         if (machineEndianness() == BSP_BIG_ENDIAN)
551         {
552                 union {unsigned char b[4]; float f;} in, out;
553                 
554                 in.f = l;
555                 out.b[0] = in.b[3];
556                 out.b[1] = in.b[2];
557                 out.b[2] = in.b[1];
558                 out.b[3] = in.b[0];
559                 
560                 return out.f;
561         }
562
563         //little endian
564         return l;
565 }
566
567 float   BspLoader::isBigFloat (float l)
568 {
569         if (machineEndianness() == BSP_BIG_ENDIAN)
570         {
571                 return l;
572         }
573         //little endian
574         union {unsigned char b[4]; float f;} in, out;
575         
576         in.f = l;
577         out.b[0] = in.b[3];
578         out.b[1] = in.b[2];
579         out.b[2] = in.b[1];
580         out.b[3] = in.b[0];
581         
582         return out.f;
583 }
584
585
586
587
588
589
590 //
591 // swapBlock
592 // If all values are 32 bits, this can be used to swap everything
593 //
594
595 void BspLoader::swapBlock( int *block, int sizeOfBlock ) {
596         int             i;
597
598         sizeOfBlock >>= 2;
599         for ( i = 0 ; i < sizeOfBlock ; i++ ) {
600                 block[i] = isLittleLong( block[i] );
601         }
602 }
603
604 //
605 // copyLump
606 //
607
608 int BspLoader::copyLump( BSPHeader      *header, int lump, void *dest, int size ) {
609         int             length, ofs;
610
611         length = header->lumps[lump].filelen;
612         ofs = header->lumps[lump].fileofs;
613         
614         //if ( length % size ) {
615         //      printf ("loadBSPFile: odd lump size");
616         //}
617
618         memcpy( dest, (unsigned char *)header + ofs, length );
619
620         return length / size;
621 }
622
623
624
625
626 //
627 // swapBSPFile
628 //
629
630 void BspLoader::swapBSPFile( void ) {
631         int                             i;
632         
633         // models       
634         swapBlock( (int *) &m_dmodels[0], m_nummodels * sizeof( m_dmodels[0] ) );
635
636         // shaders (don't swap the name)
637         for ( i = 0 ; i < m_numShaders ; i++ ) {
638                 m_dshaders[i].contentFlags = isLittleLong( m_dshaders[i].contentFlags );
639                 m_dshaders[i].surfaceFlags = isLittleLong( m_dshaders[i].surfaceFlags );
640         }
641
642         // planes
643         swapBlock( (int *)&m_dplanes[0], m_numplanes * sizeof( m_dplanes[0] ) );
644         
645         // nodes
646         swapBlock( (int *)&m_dnodes[0], m_numnodes * sizeof( m_dnodes[0] ) );
647
648         // leafs
649         swapBlock( (int *)&m_dleafs[0], m_numleafs * sizeof( m_dleafs[0] ) );
650
651         // leaffaces
652         swapBlock( (int *)&m_dleafsurfaces[0], m_numleafsurfaces * sizeof( m_dleafsurfaces[0] ) );
653
654         // leafbrushes
655         swapBlock( (int *)&m_dleafbrushes[0], m_numleafbrushes * sizeof( m_dleafbrushes[0] ) );
656
657         // brushes
658         swapBlock( (int *)&m_dbrushes[0], m_numbrushes * sizeof( m_dbrushes[0] ) );
659
660         // brushsides
661         swapBlock( (int *)&m_dbrushsides[0], m_numbrushsides * sizeof( m_dbrushsides[0] ) );
662
663         // vis
664         ((int *)&m_visBytes)[0] = isLittleLong( ((int *)&m_visBytes)[0] );
665         ((int *)&m_visBytes)[1] = isLittleLong( ((int *)&m_visBytes)[1] );
666
667
668         // drawindexes
669         swapBlock( (int *)&m_drawIndexes[0], m_numDrawIndexes * sizeof( m_drawIndexes[0] ) );
670
671         // drawsurfs
672         swapBlock( (int *)&m_drawSurfaces[0], m_numDrawSurfaces * sizeof( m_drawSurfaces[0] ) );
673
674 }
675
676
677
678
679
680 bool BspLoader::findVectorByName(float* outvec,const char* name)
681 {
682         const char *cl;
683         BSPVector3 origin;
684         
685         bool found = false;
686
687         parseEntities();
688
689         for ( int i = 1; i < m_num_entities; i++ ) {
690                 cl = getValueForKey (&m_entities[i], "classname");
691                 if ( !strcmp( cl, "info_player_start" ) ) {
692                                 getVectorForKey( &m_entities[i], "origin", origin );
693                                 found = true;
694                                 break;
695                         }
696                 if ( !strcmp( cl, "info_player_deathmatch" ) ) {
697                                 getVectorForKey( &m_entities[i], "origin", origin );
698                                 found = true;
699                                 break;
700                         }
701         }
702
703         if (found)
704         {
705                 outvec[0] = origin[0];
706                 outvec[1] = origin[1];
707                 outvec[2] = origin[2];
708         }
709         return found;
710 }
711   
712
713
714 const BSPEntity * BspLoader::getEntityByValue( const char* name, const char* value)
715 {
716         const BSPEntity* entity = NULL;
717
718         for ( int i = 1; i < m_num_entities; i++ ) {
719
720                 const BSPEntity& ent = m_entities[i];
721
722                 const char* cl = getValueForKey (&m_entities[i], name);
723                 if ( !strcmp( cl, value ) ) {
724                         entity = &ent;
725                         break;
726                 }
727         }
728         return entity;
729 }
730