2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
5 This file is part of Quake III Arena source code.
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.
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.
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 ===========================================================================
24 #include "BspLoader.h"
31 char *buffer,*script_p,*end_p;
35 #define MAX_INCLUDES 8
36 BSPScript scriptstack[MAX_INCLUDES];
40 char token[BSPMAXTOKEN];
42 bool tokenready; // only true if UnGetToken was just called
50 BspLoader::BspLoader()
53 m_Endianness = getMachineEndianness();
54 if (m_Endianness == BSP_BIG_ENDIAN)
56 printf("Machine is BIG_ENDIAN\n");
59 printf("Machine is Little Endian\n");
64 bool BspLoader::loadBSPFile( void* memoryBuffer) {
66 BSPHeader *header = (BSPHeader*) memoryBuffer;
68 // load the file header
72 swapBlock( (int *)header, sizeof(*header) );
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) );
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) );
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) );
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) );
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) );
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]) );
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]) );
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) );
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) );
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) );
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]) );
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 );
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 );
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);
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 );
148 const char* BspLoader::getValueForKey( const BSPEntity* ent, const char* key ) const {
150 const BSPKeyValuePair* ep;
152 for (ep=ent->epairs ; ep ; ep=ep->next) {
153 if (!strcmp(ep->key, key) ) {
160 float BspLoader::getFloatForKey( const BSPEntity *ent, const char *key ) {
163 k = getValueForKey( ent, key );
164 return float(atof(k));
167 bool BspLoader::getVectorForKey( const BSPEntity *ent, const char *key, BSPVector3 vec ) {
170 k = getValueForKey (ent, key);
173 sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
187 void BspLoader::parseFromMemory (char *buffer, int size)
189 script = scriptstack;
191 if (script == &scriptstack[MAX_INCLUDES])
193 //printf("script file exceeded MAX_INCLUDES");
195 strcpy (script->filename, "memory buffer" );
197 script->buffer = buffer;
199 script->script_p = script->buffer;
200 script->end_p = script->buffer + size;
207 bool BspLoader::isEndOfScript (bool crossline)
210 //printf("Line %i is incomplete\n",scriptline);
212 if (!strcmp (script->filename, "memory buffer"))
218 //free (script->buffer);
219 if (script == scriptstack+1)
225 scriptline = script->line;
226 //printf ("returning to %s\n", script->filename);
227 return getToken (crossline);
236 bool BspLoader::getToken (bool crossline)
240 if (tokenready) // is a token allready waiting?
246 if (script->script_p >= script->end_p)
247 return isEndOfScript (crossline);
253 while (*script->script_p <= 32)
255 if (script->script_p >= script->end_p)
256 return isEndOfScript (crossline);
257 if (*script->script_p++ == '\n')
261 //printf("Line %i is incomplete\n",scriptline);
263 scriptline = script->line++;
267 if (script->script_p >= script->end_p)
268 return isEndOfScript (crossline);
271 if (*script->script_p == ';' || *script->script_p == '#'
272 || ( script->script_p[0] == '/' && script->script_p[1] == '/') )
276 //printf("Line %i is incomplete\n",scriptline);
278 while (*script->script_p++ != '\n')
279 if (script->script_p >= script->end_p)
280 return isEndOfScript (crossline);
281 scriptline = script->line++;
286 if (script->script_p[0] == '/' && script->script_p[1] == '*')
290 //printf("Line %i is incomplete\n",scriptline);
293 while (script->script_p[0] != '*' && script->script_p[1] != '/')
295 if ( *script->script_p == '\n' ) {
296 scriptline = script->line++;
299 if (script->script_p >= script->end_p)
300 return isEndOfScript (crossline);
302 script->script_p += 2;
311 if (*script->script_p == '"')
315 while (*script->script_p != '"')
317 *token_p++ = *script->script_p++;
318 if (script->script_p == script->end_p)
320 if (token_p == &token[BSPMAXTOKEN])
322 //printf ("Token too large on line %i\n",scriptline);
327 else // regular token
328 while ( *script->script_p > 32 && *script->script_p != ';')
330 *token_p++ = *script->script_p++;
331 if (script->script_p == script->end_p)
333 if (token_p == &token[BSPMAXTOKEN])
335 //printf ("Token too large on line %i\n",scriptline);
341 if (!strcmp (token, "$include"))
344 //AddScriptToStack (token);
345 return false;//getToken (crossline);
351 char *BspLoader::copystring(const char *s)
354 b = (char*) malloc( strlen(s)+1);
359 void BspLoader::stripTrailing( char *e ) {
363 while (s >= e && *s <= 32)
374 BSPKeyValuePair *BspLoader::parseEpair( void ) {
377 e = (struct BSPPair*) malloc( sizeof(BSPKeyValuePair));
378 memset( e, 0, sizeof(BSPKeyValuePair) );
380 if ( strlen(token) >= BSPMAX_KEY-1 ) {
381 //printf ("ParseEpar: token too long");
383 e->key = copystring( token );
385 if ( strlen(token) >= BSPMAX_VALUE-1 ) {
387 //printf ("ParseEpar: token too long");
389 e->value = copystring( token );
391 // strip trailing spaces that sometimes get accidentally
392 // added in the editor
393 stripTrailing( e->key );
394 stripTrailing( e->value );
405 bool BspLoader::parseEntity( void ) {
409 if ( !getToken (true) ) {
413 if ( strcmp (token, "{") ) {
415 //printf ("parseEntity: { not found");
421 bla.firstDrawSurf = 0;
427 m_entities.push_back(bla);
428 mapent = &m_entities[m_entities.size()-1];
432 if ( !getToken (true) ) {
433 //printf("parseEntity: EOF without closing brace");
435 if ( !strcmp (token, "}") ) {
438 e = (struct BSPPair*)parseEpair ();
439 e->next = mapent->epairs;
450 Parses the dentdata string into entities
453 void BspLoader::parseEntities( void ) {
457 parseFromMemory( &m_dentdata[0], m_entdatasize );
459 while ( parseEntity () ) {
465 int BspLoader::getMachineEndianness()
468 const char *p = (const char *) &i;
469 if (p[0] == 1) // Lowest address contains the least significant byte
470 return BSP_LITTLE_ENDIAN;
472 return BSP_BIG_ENDIAN;
475 short BspLoader::isLittleShort (short l)
477 if (machineEndianness() == BSP_BIG_ENDIAN)
490 short BspLoader::isBigShort (short l)
492 if (machineEndianness() == BSP_BIG_ENDIAN)
509 int BspLoader::isLittleLong (int l)
511 if (machineEndianness() == BSP_BIG_ENDIAN)
513 unsigned char b1,b2,b3,b4;
520 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
528 int BspLoader::isBigLong (int l)
530 if (machineEndianness() == BSP_BIG_ENDIAN)
536 unsigned char b1,b2,b3,b4;
543 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
548 float BspLoader::isLittleFloat (float l)
550 if (machineEndianness() == BSP_BIG_ENDIAN)
552 union {unsigned char b[4]; float f;} in, out;
567 float BspLoader::isBigFloat (float l)
569 if (machineEndianness() == BSP_BIG_ENDIAN)
574 union {unsigned char b[4]; float f;} in, out;
592 // If all values are 32 bits, this can be used to swap everything
595 void BspLoader::swapBlock( int *block, int sizeOfBlock ) {
599 for ( i = 0 ; i < sizeOfBlock ; i++ ) {
600 block[i] = isLittleLong( block[i] );
608 int BspLoader::copyLump( BSPHeader *header, int lump, void *dest, int size ) {
611 length = header->lumps[lump].filelen;
612 ofs = header->lumps[lump].fileofs;
614 //if ( length % size ) {
615 // printf ("loadBSPFile: odd lump size");
618 memcpy( dest, (unsigned char *)header + ofs, length );
620 return length / size;
630 void BspLoader::swapBSPFile( void ) {
634 swapBlock( (int *) &m_dmodels[0], m_nummodels * sizeof( m_dmodels[0] ) );
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 );
643 swapBlock( (int *)&m_dplanes[0], m_numplanes * sizeof( m_dplanes[0] ) );
646 swapBlock( (int *)&m_dnodes[0], m_numnodes * sizeof( m_dnodes[0] ) );
649 swapBlock( (int *)&m_dleafs[0], m_numleafs * sizeof( m_dleafs[0] ) );
652 swapBlock( (int *)&m_dleafsurfaces[0], m_numleafsurfaces * sizeof( m_dleafsurfaces[0] ) );
655 swapBlock( (int *)&m_dleafbrushes[0], m_numleafbrushes * sizeof( m_dleafbrushes[0] ) );
658 swapBlock( (int *)&m_dbrushes[0], m_numbrushes * sizeof( m_dbrushes[0] ) );
661 swapBlock( (int *)&m_dbrushsides[0], m_numbrushsides * sizeof( m_dbrushsides[0] ) );
664 ((int *)&m_visBytes)[0] = isLittleLong( ((int *)&m_visBytes)[0] );
665 ((int *)&m_visBytes)[1] = isLittleLong( ((int *)&m_visBytes)[1] );
669 swapBlock( (int *)&m_drawIndexes[0], m_numDrawIndexes * sizeof( m_drawIndexes[0] ) );
672 swapBlock( (int *)&m_drawSurfaces[0], m_numDrawSurfaces * sizeof( m_drawSurfaces[0] ) );
680 bool BspLoader::findVectorByName(float* outvec,const char* name)
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 );
696 if ( !strcmp( cl, "info_player_deathmatch" ) ) {
697 getVectorForKey( &m_entities[i], "origin", origin );
705 outvec[0] = origin[0];
706 outvec[1] = origin[1];
707 outvec[2] = origin[2];
714 const BSPEntity * BspLoader::getEntityByValue( const char* name, const char* value)
716 const BSPEntity* entity = NULL;
718 for ( int i = 1; i < m_num_entities; i++ ) {
720 const BSPEntity& ent = m_entities[i];
722 const char* cl = getValueForKey (&m_entities[i], name);
723 if ( !strcmp( cl, value ) ) {