/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "eclass_def.h" #include "iscriplib.h" #include "ifilesystem.h" #include "iarchive.h" #include "eclasslib.h" #include "stream/stringstream.h" #include "stream/textfilestream.h" #include "modulesystem/moduleregistry.h" #include "os/path.h" const char* EClass_GetExtension(){ return "def"; } void Eclass_ScanFile( EntityClassCollector& collector, const char *filename ); #include "modulesystem/singletonmodule.h" class EntityClassDefDependencies : public GlobalShaderCacheModuleRef, public GlobalScripLibModuleRef { }; class EclassDefAPI { EntityClassScanner m_eclassdef; public: typedef EntityClassScanner Type; STRING_CONSTANT( Name, "def" ); EclassDefAPI(){ m_eclassdef.scanFile = &Eclass_ScanFile; m_eclassdef.getExtension = &EClass_GetExtension; } EntityClassScanner* getTable(){ return &m_eclassdef; } }; typedef SingletonModule EclassDefModule; typedef Static StaticEclassDefModule; StaticRegisterModule staticRegisterEclassDef( StaticEclassDefModule::instance() ); #include "string/string.h" #include char com_token[1024]; bool com_eof; /* ============== COM_Parse Parse a token out of a string ============== */ const char *COM_Parse( const char *data ){ int c; int len; len = 0; com_token[0] = 0; if ( !data ) { return 0; } // skip whitespace skipwhite: while ( ( c = *data ) <= ' ' ) { if ( c == 0 ) { com_eof = true; return 0; // end of file; } data++; } // skip // comments if ( c == '/' && data[1] == '/' ) { while ( *data && *data != '\n' ) data++; goto skipwhite; } // handle quoted strings specially if ( c == '\"' ) { data++; do { c = *data++; if ( c == '\"' ) { com_token[len] = 0; return data; } com_token[len] = c; len++; } while ( 1 ); } // parse single characters if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { com_token[len] = c; len++; com_token[len] = 0; return data + 1; } // parse a regular word do { com_token[len] = c; data++; len++; c = *data; if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) { break; } } while ( c > 32 ); com_token[len] = 0; return data; } const char* Get_COM_Token(){ return com_token; } const char *debugname; void setSpecialLoad( EntityClass *e, const char* pWhat, CopiedString& p ){ // Hydra: removed some amazingly bad cstring usage, whoever wrote that // needs to be taken out and shot. const char *pText = 0; const char *where = 0; where = strstr( e->comments(),pWhat ); if ( !where ) { return; } pText = where + strlen( pWhat ); if ( *pText == '\"' ) { pText++; } where = strchr( pText,'\"' ); if ( where ) { p = StringRange( pText, where ); } else { p = pText; } } #include "eclasslib.h" /* the classname, color triple, and bounding box are parsed out of comments A ? size means take the exact brush size. / *QUAKED (0 0 0) ? / *QUAKED (0 0 0) (-8 -8 -8) (8 8 8) Flag names can follow the size description: / *QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY */ EntityClass *Eclass_InitFromText( const char *text ){ EntityClass* e = Eclass_Alloc(); e->free = &Eclass_Free; // grab the name text = COM_Parse( text ); e->m_name = Get_COM_Token(); debugname = e->name(); { // grab the color, reformat as texture name int r = sscanf( text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2] ); if ( r != 3 ) { return e; } eclass_capture_state( e ); } while ( *text != ')' ) { if ( !*text ) { return 0; } text++; } text++; // get the size text = COM_Parse( text ); if ( Get_COM_Token()[0] == '(' ) { // parse the size as two vectors e->fixedsize = true; int r = sscanf( text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], &e->maxs[0], &e->maxs[1], &e->maxs[2] ); if ( r != 6 ) { return 0; } for ( int i = 0 ; i < 2 ; i++ ) { while ( *text != ')' ) { if ( !*text ) { return 0; } text++; } text++; } } char parms[256]; // get the flags { // copy to the first /n char* p = parms; while ( *text && *text != '\n' ) *p++ = *text++; *p = 0; text++; } { // any remaining words are parm flags const char* p = parms; for ( std::size_t i = 0 ; i < MAX_FLAGS ; i++ ) { p = COM_Parse( p ); if ( !p ) { break; } strcpy( e->flagnames[i], Get_COM_Token() ); } } e->m_comments = text; setSpecialLoad( e, "model=", e->m_modelpath ); StringOutputStream buffer( string_length( e->m_modelpath.c_str() ) ); buffer << PathCleaned( e->m_modelpath.c_str() ); e->m_modelpath = buffer.c_str(); if ( !e->fixedsize ) { EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction", "0" ) ); } else { EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "angle", "Yaw Angle", "0" ) ); } EntityClass_insertAttribute( *e, "model", EntityClassAttribute( "model", "Model" ) ); EntityClass_insertAttribute( *e, "noise", EntityClassAttribute( "sound", "Sound" ) ); return e; } void Eclass_ScanFile( EntityClassCollector& collector, const char *filename ){ EntityClass *e; TextFileInputStream inputFile( filename ); if ( inputFile.failed() ) { globalErrorStream() << "ScanFile: " << filename << " not found\n"; return; } globalOutputStream() << "ScanFile: " << filename << "\n"; enum EParserState { eParseDefault, eParseSolidus, eParseComment, eParseQuakeED, eParseEntityClass, eParseEntityClassEnd, } state = eParseDefault; const char* quakeEd = "QUAKED"; const char* p = 0; StringBuffer buffer; SingleCharacterInputStream bufferedInput( inputFile ); for (;; ) { char c; if ( !bufferedInput.readChar( c ) ) { break; } switch ( state ) { case eParseDefault: if ( c == '/' ) { state = eParseSolidus; } break; case eParseSolidus: if ( c == '/' ) { state = eParseComment; } else if ( c == '*' ) { p = quakeEd; state = eParseQuakeED; } break; case eParseComment: if ( c == '\n' ) { state = eParseDefault; } break; case eParseQuakeED: if ( c == *p ) { if ( *( ++p ) == '\0' ) { state = eParseEntityClass; } } else { state = eParseDefault; } break; case eParseEntityClass: if ( c == '*' ) { state = eParseEntityClassEnd; } else { buffer.push_back( c ); } break; case eParseEntityClassEnd: if ( c == '/' ) { e = Eclass_InitFromText( buffer.c_str() ); state = eParseDefault; if ( e ) { collector.insert( e ); } else{ globalErrorStream() << "Error parsing: " << debugname << " in " << filename << "\n"; } buffer.clear(); state = eParseDefault; } else { buffer.push_back( '*' ); buffer.push_back( c ); state = eParseEntityClass; } break; } } }