2006-02-10 22:01:20 +00:00
/*
Copyright ( C ) 2001 - 2006 , William Joseph .
All Rights Reserved .
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_doom3.h"
# include "debugging/debugging.h"
# include <map>
# include "ifilesystem.h"
# include "iscriplib.h"
# include "iarchive.h"
# include "qerplugin.h"
# include "generic/callback.h"
# include "string/string.h"
# include "eclasslib.h"
# include "os/path.h"
# include "os/dir.h"
# include "stream/stringstream.h"
# include "moduleobservers.h"
# include "stringio.h"
class RawString
{
const char * m_value ;
public :
RawString ( const char * value ) : m_value ( value )
{
}
const char * c_str ( ) const
{
return m_value ;
}
} ;
inline bool operator < ( const RawString & self , const RawString & other )
{
return string_less_nocase ( self . c_str ( ) , other . c_str ( ) ) ;
}
typedef std : : map < RawString , EntityClass * > EntityClasses ;
EntityClasses g_EntityClassDoom3_classes ;
EntityClass * g_EntityClassDoom3_bad = 0 ;
void EntityClassDoom3_clear ( )
{
for ( EntityClasses : : iterator i = g_EntityClassDoom3_classes . begin ( ) ; i ! = g_EntityClassDoom3_classes . end ( ) ; + + i )
{
( * i ) . second - > free ( ( * i ) . second ) ;
}
g_EntityClassDoom3_classes . clear ( ) ;
}
// entityClass will be inserted only if another of the same name does not already exist.
// if entityClass was inserted, the same object is returned, otherwise the already-existing object is returned.
EntityClass * EntityClassDoom3_insertUnique ( EntityClass * entityClass )
{
return ( * g_EntityClassDoom3_classes . insert ( EntityClasses : : value_type ( entityClass - > name ( ) , entityClass ) ) . first ) . second ;
}
void EntityClassDoom3_forEach ( EntityClassVisitor & visitor )
{
for ( EntityClasses : : iterator i = g_EntityClassDoom3_classes . begin ( ) ; i ! = g_EntityClassDoom3_classes . end ( ) ; + + i )
{
visitor . visit ( ( * i ) . second ) ;
}
}
2006-08-22 17:37:07 +00:00
inline void printParseError ( const char * message )
{
globalErrorStream ( ) < < message ;
}
# define PARSE_RETURN_FALSE_IF_FAIL(expression) if(!(expression)) { printParseError(FILE_LINE "\nparse failed: " #expression "\n"); return false; } else
bool EntityClassDoom3_parseToken ( Tokeniser & tokeniser )
{
const char * token = tokeniser . getToken ( ) ;
PARSE_RETURN_FALSE_IF_FAIL ( token ! = 0 ) ;
return true ;
}
bool EntityClassDoom3_parseToken ( Tokeniser & tokeniser , const char * string )
{
const char * token = tokeniser . getToken ( ) ;
PARSE_RETURN_FALSE_IF_FAIL ( token ! = 0 ) ;
return string_equal ( token , string ) ;
}
bool EntityClassDoom3_parseString ( Tokeniser & tokeniser , const char * & s )
{
const char * token = tokeniser . getToken ( ) ;
PARSE_RETURN_FALSE_IF_FAIL ( token ! = 0 ) ;
s = token ;
return true ;
}
bool EntityClassDoom3_parseString ( Tokeniser & tokeniser , CopiedString & s )
{
const char * token = tokeniser . getToken ( ) ;
PARSE_RETURN_FALSE_IF_FAIL ( token ! = 0 ) ;
s = token ;
return true ;
}
bool EntityClassDoom3_parseString ( Tokeniser & tokeniser , StringOutputStream & s )
{
const char * token = tokeniser . getToken ( ) ;
PARSE_RETURN_FALSE_IF_FAIL ( token ! = 0 ) ;
s < < token ;
return true ;
}
bool EntityClassDoom3_parseUnknown ( Tokeniser & tokeniser )
2006-02-10 22:01:20 +00:00
{
//const char* name =
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
2006-02-10 22:01:20 +00:00
//globalOutputStream() << "parsing unknown block " << makeQuoted(name) << "\n";
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser , " { " ) ) ;
2006-02-10 22:01:20 +00:00
tokeniser . nextLine ( ) ;
std : : size_t depth = 1 ;
for ( ; ; )
{
2006-08-22 17:37:07 +00:00
const char * token ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , token ) ) ;
2006-02-10 22:01:20 +00:00
if ( string_equal ( token , " } " ) )
{
if ( - - depth = = 0 )
{
tokeniser . nextLine ( ) ;
break ;
}
}
else if ( string_equal ( token , " { " ) )
{
+ + depth ;
}
tokeniser . nextLine ( ) ;
}
2006-08-22 17:37:07 +00:00
return true ;
2006-02-10 22:01:20 +00:00
}
class Model
{
public :
bool m_resolved ;
CopiedString m_mesh ;
CopiedString m_skin ;
CopiedString m_parent ;
typedef std : : map < CopiedString , CopiedString > Anims ;
Anims m_anims ;
Model ( ) : m_resolved ( false )
{
}
} ;
typedef std : : map < CopiedString , Model > Models ;
Models g_models ;
void Model_resolveInheritance ( const char * name , Model & model )
{
if ( model . m_resolved = = false )
{
model . m_resolved = true ;
if ( ! string_empty ( model . m_parent . c_str ( ) ) )
{
Models : : iterator i = g_models . find ( model . m_parent ) ;
if ( i = = g_models . end ( ) )
{
globalErrorStream ( ) < < " model " < < name < < " inherits unknown model " < < model . m_parent . c_str ( ) < < " \n " ;
}
else
{
Model_resolveInheritance ( ( * i ) . first . c_str ( ) , ( * i ) . second ) ;
model . m_mesh = ( * i ) . second . m_mesh ;
model . m_skin = ( * i ) . second . m_skin ;
}
}
}
}
2006-08-22 17:37:07 +00:00
bool EntityClassDoom3_parseModel ( Tokeniser & tokeniser )
2006-02-10 22:01:20 +00:00
{
2006-08-22 17:37:07 +00:00
const char * name ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , name ) ) ;
2006-02-10 22:01:20 +00:00
Model & model = g_models [ name ] ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser , " { " ) ) ;
2006-02-10 22:01:20 +00:00
tokeniser . nextLine ( ) ;
for ( ; ; )
{
2006-08-22 17:37:07 +00:00
const char * parameter ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , parameter ) ) ;
2006-02-10 22:01:20 +00:00
if ( string_equal ( parameter , " } " ) )
{
tokeniser . nextLine ( ) ;
break ;
}
else if ( string_equal ( parameter , " inherit " ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , model . m_parent ) ) ;
tokeniser . nextLine ( ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( parameter , " remove " ) )
{
//const char* remove =
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
tokeniser . nextLine ( ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( parameter , " mesh " ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , model . m_mesh ) ) ;
tokeniser . nextLine ( ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( parameter , " skin " ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , model . m_skin ) ) ;
tokeniser . nextLine ( ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( parameter , " offset " ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser , " ( " ) ) ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser , " ) " ) ) ;
2006-02-10 22:01:20 +00:00
tokeniser . nextLine ( ) ;
}
else if ( string_equal ( parameter , " channel " ) )
{
//const char* channelName =
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser , " ( " ) ) ;
2006-02-10 22:01:20 +00:00
for ( ; ; )
{
2006-08-22 17:37:07 +00:00
const char * end ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , end ) ) ;
2006-02-10 22:01:20 +00:00
if ( string_equal ( end , " ) " ) )
{
tokeniser . nextLine ( ) ;
break ;
}
}
}
else if ( string_equal ( parameter , " anim " ) )
{
2006-08-22 17:37:07 +00:00
CopiedString animName ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , animName ) ) ;
const char * animFile ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , animFile ) ) ;
2006-02-10 22:01:20 +00:00
model . m_anims . insert ( Model : : Anims : : value_type ( animName , animFile ) ) ;
2006-08-22 17:37:07 +00:00
const char * token ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , token ) ) ;
2006-02-10 22:01:20 +00:00
while ( string_equal ( token , " , " ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , animFile ) ) ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , token ) ) ;
2006-02-10 22:01:20 +00:00
}
if ( string_equal ( token , " { " ) )
{
for ( ; ; )
{
2006-08-22 17:37:07 +00:00
const char * end ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , end ) ) ;
2006-02-10 22:01:20 +00:00
if ( string_equal ( end , " } " ) )
{
tokeniser . nextLine ( ) ;
break ;
}
tokeniser . nextLine ( ) ;
}
}
else
{
tokeniser . ungetToken ( ) ;
}
}
else
{
2006-08-22 17:37:07 +00:00
globalErrorStream ( ) < < " unknown model parameter: " < < makeQuoted ( parameter ) < < " \n " ;
return false ;
2006-02-10 22:01:20 +00:00
}
tokeniser . nextLine ( ) ;
}
2006-08-22 17:37:07 +00:00
return true ;
2006-02-10 22:01:20 +00:00
}
inline bool char_isSpaceOrTab ( char c )
{
return c = = ' ' | | c = = ' \t ' ;
}
inline bool char_isNotSpaceOrTab ( char c )
{
return ! char_isSpaceOrTab ( c ) ;
}
template < typename Predicate >
inline const char * string_find_if ( const char * string , Predicate predicate )
{
for ( ; * string ! = 0 ; + + string )
{
if ( predicate ( * string ) )
{
return string ;
}
}
return string ;
}
inline const char * string_findFirstSpaceOrTab ( const char * string )
{
return string_find_if ( string , char_isSpaceOrTab ) ;
}
inline const char * string_findFirstNonSpaceOrTab ( const char * string )
{
return string_find_if ( string , char_isNotSpaceOrTab ) ;
}
2006-08-22 17:37:07 +00:00
static bool EntityClass_parse ( EntityClass & entityClass , Tokeniser & tokeniser )
2006-02-10 22:01:20 +00:00
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , entityClass . m_name ) ) ;
2006-02-10 22:01:20 +00:00
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser , " { " ) ) ;
2006-02-10 22:01:20 +00:00
tokeniser . nextLine ( ) ;
StringOutputStream usage ( 256 ) ;
StringOutputStream description ( 256 ) ;
CopiedString * currentDescription = 0 ;
StringOutputStream * currentString = 0 ;
for ( ; ; )
{
2006-08-22 17:37:07 +00:00
const char * key ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , key ) ) ;
2006-02-10 22:01:20 +00:00
const char * last = string_findFirstSpaceOrTab ( key ) ;
2006-02-26 22:27:38 +00:00
CopiedString first ( StringRange ( key , last ) ) ;
2006-02-10 22:01:20 +00:00
if ( ! string_empty ( last ) )
{
last = string_findFirstNonSpaceOrTab ( last ) ;
}
if ( currentString ! = 0 & & string_equal ( key , " \\ " ) )
{
tokeniser . nextLine ( ) ;
2006-08-22 17:37:07 +00:00
* currentString < < " " ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , * currentString ) ) ;
2006-02-10 22:01:20 +00:00
continue ;
}
if ( currentDescription ! = 0 )
{
* currentDescription = description . c_str ( ) ;
description . clear ( ) ;
currentDescription = 0 ;
}
currentString = 0 ;
if ( string_equal ( key , " } " ) )
{
tokeniser . nextLine ( ) ;
break ;
}
else if ( string_equal ( key , " model " ) )
{
2006-08-22 17:37:07 +00:00
const char * token ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , token ) ) ;
entityClass . fixedsize = true ;
2006-02-10 22:01:20 +00:00
StringOutputStream buffer ( 256 ) ;
2006-08-22 17:37:07 +00:00
buffer < < PathCleaned ( token ) ;
entityClass . m_modelpath = buffer . c_str ( ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( key , " editor_color " ) )
{
2006-08-22 17:37:07 +00:00
const char * value ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , value ) ) ;
2006-02-10 22:01:20 +00:00
if ( ! string_empty ( value ) )
{
2006-08-22 17:37:07 +00:00
entityClass . colorSpecified = true ;
bool success = string_parse_vector3 ( value , entityClass . color ) ;
2006-02-10 22:01:20 +00:00
ASSERT_MESSAGE ( success , " editor_color: parse error " ) ;
}
}
else if ( string_equal ( key , " editor_ragdoll " ) )
{
//bool ragdoll = atoi(tokeniser.getToken()) != 0;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( key , " editor_mins " ) )
{
2006-08-22 17:37:07 +00:00
entityClass . sizeSpecified = true ;
const char * value ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , value ) ) ;
2006-02-10 22:01:20 +00:00
if ( ! string_empty ( value ) & & ! string_equal ( value , " ? " ) )
{
2006-08-22 17:37:07 +00:00
entityClass . fixedsize = true ;
bool success = string_parse_vector3 ( value , entityClass . mins ) ;
2006-02-10 22:01:20 +00:00
ASSERT_MESSAGE ( success , " editor_mins: parse error " ) ;
}
}
else if ( string_equal ( key , " editor_maxs " ) )
{
2006-08-22 17:37:07 +00:00
entityClass . sizeSpecified = true ;
const char * value ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , value ) ) ;
2006-02-10 22:01:20 +00:00
if ( ! string_empty ( value ) & & ! string_equal ( value , " ? " ) )
{
2006-08-22 17:37:07 +00:00
entityClass . fixedsize = true ;
bool success = string_parse_vector3 ( value , entityClass . maxs ) ;
2006-02-10 22:01:20 +00:00
ASSERT_MESSAGE ( success , " editor_maxs: parse error " ) ;
}
}
else if ( string_equal ( key , " editor_usage " ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , usage ) ) ;
2006-02-10 22:01:20 +00:00
currentString = & usage ;
}
else if ( string_equal_n ( key , " editor_usage " , 12 ) )
{
2006-08-22 17:37:07 +00:00
usage < < " \n " ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , usage ) ) ;
2006-02-10 22:01:20 +00:00
currentString = & usage ;
}
else if ( string_equal ( key , " editor_rotatable " )
| | string_equal ( key , " editor_showangle " )
| | string_equal ( key , " editor_mover " )
| | string_equal ( key , " editor_model " )
| | string_equal ( key , " editor_material " )
| | string_equal ( key , " editor_combatnode " )
| | ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_gui " ) )
| | string_equal_n ( key , " editor_copy " , 11 ) )
{
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & ( string_equal ( first . c_str ( ) , " editor_var " ) | | string_equal ( first . c_str ( ) , " editor_string " ) ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " string " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_float " ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " string " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_snd " ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " sound " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_bool " ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " boolean " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_int " ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " integer " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_model " ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " model " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & string_equal ( first . c_str ( ) , " editor_color " ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " color " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( ! string_empty ( last ) & & ( string_equal ( first . c_str ( ) , " editor_material " ) | | string_equal ( first . c_str ( ) , " editor_mat " ) ) )
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , last ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " shader " ;
currentDescription = & attribute . m_description ;
currentString = & description ;
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , description ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( key , " inherit " ) )
{
2006-08-22 17:37:07 +00:00
entityClass . inheritanceResolved = false ;
ASSERT_MESSAGE ( entityClass . m_parent . empty ( ) , " only one 'inherit' supported per entityDef " ) ;
const char * token ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , token ) ) ;
entityClass . m_parent . push_back ( token ) ;
2006-02-10 22:01:20 +00:00
}
// begin quake4-specific keys
else if ( string_equal ( key , " editor_targetonsel " ) )
{
//const char* value =
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( key , " editor_menu " ) )
{
//const char* value =
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
2006-02-10 22:01:20 +00:00
}
else if ( string_equal ( key , " editor_ignore " ) )
{
//const char* value =
2006-08-22 17:37:07 +00:00
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseToken ( tokeniser ) ) ;
2006-02-10 22:01:20 +00:00
}
// end quake4-specific keys
else
{
2006-08-22 17:37:07 +00:00
CopiedString tmp ( key ) ;
2006-02-10 22:01:20 +00:00
ASSERT_MESSAGE ( ! string_equal_n ( key , " editor_ " , 7 ) , " unsupported editor key: " < < makeQuoted ( key ) ) ;
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , key ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " string " ;
2006-08-22 17:37:07 +00:00
const char * value ;
PARSE_RETURN_FALSE_IF_FAIL ( EntityClassDoom3_parseString ( tokeniser , value ) ) ;
if ( string_equal ( value , " } " ) ) // hack for quake4 powerups.def bug
{
globalErrorStream ( ) < < " entityDef " < < makeQuoted ( entityClass . m_name . c_str ( ) ) < < " key " < < makeQuoted ( tmp . c_str ( ) ) < < " has no value \n " ;
break ;
}
else
{
attribute . m_value = value ;
}
2006-02-10 22:01:20 +00:00
}
tokeniser . nextLine ( ) ;
}
2006-08-22 17:37:07 +00:00
entityClass . m_comments = usage . c_str ( ) ;
2006-02-10 22:01:20 +00:00
2006-08-22 17:37:07 +00:00
if ( string_equal ( entityClass . m_name . c_str ( ) , " light " ) )
2006-02-10 22:01:20 +00:00
{
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , " light_radius " ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " vector3 " ;
attribute . m_value = " 300 300 300 " ;
}
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , " light_center " ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " vector3 " ;
}
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , " noshadows " ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " boolean " ;
attribute . m_value = " 0 " ;
}
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , " nospecular " ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " boolean " ;
attribute . m_value = " 0 " ;
}
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , " nodiffuse " ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " boolean " ;
attribute . m_value = " 0 " ;
}
{
2006-08-22 17:37:07 +00:00
EntityClassAttribute & attribute = EntityClass_insertAttribute ( entityClass , " falloff " ) . second ;
2006-02-10 22:01:20 +00:00
attribute . m_type = " real " ;
}
}
2006-08-22 17:37:07 +00:00
return true ;
}
bool EntityClassDoom3_parseEntityDef ( Tokeniser & tokeniser )
{
EntityClass * entityClass = Eclass_Alloc ( ) ;
entityClass - > free = & Eclass_Free ;
if ( ! EntityClass_parse ( * entityClass , tokeniser ) )
{
eclass_capture_state ( entityClass ) ; // finish constructing the entity so that it can be destroyed cleanly.
entityClass - > free ( entityClass ) ;
return false ;
}
2006-02-10 22:01:20 +00:00
EntityClass * inserted = EntityClassDoom3_insertUnique ( entityClass ) ;
if ( inserted ! = entityClass )
{
globalErrorStream ( ) < < " entityDef " < < entityClass - > name ( ) < < " is already defined, second definition ignored \n " ;
eclass_capture_state ( entityClass ) ; // finish constructing the entity so that it can be destroyed cleanly.
entityClass - > free ( entityClass ) ;
}
2006-08-22 17:37:07 +00:00
return true ;
}
bool EntityClassDoom3_parseBlock ( Tokeniser & tokeniser , const char * blockType )
{
if ( string_equal ( blockType , " entityDef " ) )
{
return EntityClassDoom3_parseEntityDef ( tokeniser ) ;
}
else if ( string_equal ( blockType , " model " ) )
{
return EntityClassDoom3_parseModel ( tokeniser ) ;
}
else
{
return EntityClassDoom3_parseUnknown ( tokeniser ) ;
}
2006-02-10 22:01:20 +00:00
}
2006-08-22 17:37:07 +00:00
bool EntityClassDoom3_parse ( TextInputStream & inputStream , const char * filename )
2006-02-10 22:01:20 +00:00
{
Tokeniser & tokeniser = GlobalScriptLibrary ( ) . m_pfnNewScriptTokeniser ( inputStream ) ;
tokeniser . nextLine ( ) ;
for ( ; ; )
{
const char * blockType = tokeniser . getToken ( ) ;
if ( blockType = = 0 )
{
2006-08-22 17:37:07 +00:00
return true ;
2006-02-10 22:01:20 +00:00
}
2006-08-22 17:37:07 +00:00
CopiedString tmp ( blockType ) ;
if ( ! EntityClassDoom3_parseBlock ( tokeniser , tmp . c_str ( ) ) )
2006-02-10 22:01:20 +00:00
{
2006-08-22 17:37:07 +00:00
globalErrorStream ( ) < < GlobalFileSystem ( ) . findFile ( filename ) < < filename < < " : " < < tokeniser . getLine ( ) < < " : " < < tmp . c_str ( ) < < " parse failed, skipping rest of file \n " ;
return false ;
2006-02-10 22:01:20 +00:00
}
}
tokeniser . release ( ) ;
}
void EntityClassDoom3_loadFile ( const char * filename )
{
globalOutputStream ( ) < < " parsing entity classes from " < < makeQuoted ( filename ) < < " \n " ;
StringOutputStream fullname ( 256 ) ;
fullname < < " def/ " < < filename ;
ArchiveTextFile * file = GlobalFileSystem ( ) . openTextFile ( fullname . c_str ( ) ) ;
if ( file ! = 0 )
{
2006-08-22 17:37:07 +00:00
EntityClassDoom3_parse ( file - > getInputStream ( ) , fullname . c_str ( ) ) ;
2006-02-10 22:01:20 +00:00
file - > release ( ) ;
}
}
EntityClass * EntityClassDoom3_findOrInsert ( const char * name , bool has_brushes )
{
ASSERT_NOTNULL ( name ) ;
if ( string_empty ( name ) )
{
return g_EntityClassDoom3_bad ;
}
EntityClasses : : iterator i = g_EntityClassDoom3_classes . find ( name ) ;
if ( i ! = g_EntityClassDoom3_classes . end ( )
//&& string_equal((*i).first, name)
)
{
return ( * i ) . second ;
}
EntityClass * e = EntityClass_Create_Default ( name , has_brushes ) ;
EntityClass * inserted = EntityClassDoom3_insertUnique ( e ) ;
ASSERT_MESSAGE ( inserted = = e , " " ) ;
return inserted ;
}
const ListAttributeType * EntityClassDoom3_findListType ( const char * name )
{
return 0 ;
}
void EntityClass_resolveInheritance ( EntityClass * derivedClass )
{
if ( derivedClass - > inheritanceResolved = = false )
{
derivedClass - > inheritanceResolved = true ;
EntityClasses : : iterator i = g_EntityClassDoom3_classes . find ( derivedClass - > m_parent . front ( ) . c_str ( ) ) ;
if ( i = = g_EntityClassDoom3_classes . end ( ) )
{
globalErrorStream ( ) < < " failed to find entityDef " < < makeQuoted ( derivedClass - > m_parent . front ( ) . c_str ( ) ) < < " inherited by " < < makeQuoted ( derivedClass - > m_name . c_str ( ) ) < < " \n " ;
}
else
{
EntityClass * parentClass = ( * i ) . second ;
EntityClass_resolveInheritance ( parentClass ) ;
if ( ! derivedClass - > colorSpecified )
{
derivedClass - > colorSpecified = parentClass - > colorSpecified ;
derivedClass - > color = parentClass - > color ;
}
if ( ! derivedClass - > sizeSpecified )
{
derivedClass - > sizeSpecified = parentClass - > sizeSpecified ;
derivedClass - > mins = parentClass - > mins ;
derivedClass - > maxs = parentClass - > maxs ;
derivedClass - > fixedsize = parentClass - > fixedsize ;
}
for ( EntityClassAttributes : : iterator j = parentClass - > m_attributes . begin ( ) ; j ! = parentClass - > m_attributes . end ( ) ; + + j )
{
EntityClass_insertAttribute ( * derivedClass , ( * j ) . first . c_str ( ) , ( * j ) . second ) ;
}
}
}
}
class EntityClassDoom3 : public ModuleObserver
{
std : : size_t m_unrealised ;
ModuleObservers m_observers ;
public :
EntityClassDoom3 ( ) : m_unrealised ( 2 )
{
}
void realise ( )
{
if ( - - m_unrealised = = 0 )
{
globalOutputStream ( ) < < " searching vfs directory " < < makeQuoted ( " def " ) < < " for *.def \n " ;
GlobalFileSystem ( ) . forEachFile ( " def/ " , " def " , FreeCaller1 < const char * , EntityClassDoom3_loadFile > ( ) ) ;
{
for ( Models : : iterator i = g_models . begin ( ) ; i ! = g_models . end ( ) ; + + i )
{
Model_resolveInheritance ( ( * i ) . first . c_str ( ) , ( * i ) . second ) ;
}
}
{
for ( EntityClasses : : iterator i = g_EntityClassDoom3_classes . begin ( ) ; i ! = g_EntityClassDoom3_classes . end ( ) ; + + i )
{
EntityClass_resolveInheritance ( ( * i ) . second ) ;
if ( ! string_empty ( ( * i ) . second - > m_modelpath . c_str ( ) ) )
{
Models : : iterator j = g_models . find ( ( * i ) . second - > m_modelpath ) ;
if ( j ! = g_models . end ( ) )
{
( * i ) . second - > m_modelpath = ( * j ) . second . m_mesh ;
( * i ) . second - > m_skin = ( * j ) . second . m_skin ;
}
}
eclass_capture_state ( ( * i ) . second ) ;
StringOutputStream usage ( 256 ) ;
usage < < " -------- KEYS -------- \n " ;
for ( EntityClassAttributes : : iterator j = ( * i ) . second - > m_attributes . begin ( ) ; j ! = ( * i ) . second - > m_attributes . end ( ) ; + + j )
{
const char * name = EntityClassAttributePair_getName ( * j ) ;
const char * description = EntityClassAttributePair_getDescription ( * j ) ;
if ( ! string_equal ( name , description ) )
{
usage < < EntityClassAttributePair_getName ( * j ) < < " : " < < EntityClassAttributePair_getDescription ( * j ) < < " \n " ;
}
}
( * i ) . second - > m_comments = usage . c_str ( ) ;
}
}
m_observers . realise ( ) ;
}
}
void unrealise ( )
{
if ( + + m_unrealised = = 1 )
{
m_observers . unrealise ( ) ;
EntityClassDoom3_clear ( ) ;
}
}
void attach ( ModuleObserver & observer )
{
m_observers . attach ( observer ) ;
}
void detach ( ModuleObserver & observer )
{
m_observers . detach ( observer ) ;
}
} ;
EntityClassDoom3 g_EntityClassDoom3 ;
void EntityClassDoom3_attach ( ModuleObserver & observer )
{
g_EntityClassDoom3 . attach ( observer ) ;
}
void EntityClassDoom3_detach ( ModuleObserver & observer )
{
g_EntityClassDoom3 . detach ( observer ) ;
}
void EntityClassDoom3_realise ( )
{
g_EntityClassDoom3 . realise ( ) ;
}
void EntityClassDoom3_unrealise ( )
{
g_EntityClassDoom3 . unrealise ( ) ;
}
void EntityClassDoom3_construct ( )
{
GlobalFileSystem ( ) . attach ( g_EntityClassDoom3 ) ;
// start by creating the default unknown eclass
g_EntityClassDoom3_bad = EClass_Create ( " UNKNOWN_CLASS " , Vector3 ( 0.0f , 0.5f , 0.0f ) , " " ) ;
EntityClassDoom3_realise ( ) ;
}
void EntityClassDoom3_destroy ( )
{
EntityClassDoom3_unrealise ( ) ;
g_EntityClassDoom3_bad - > free ( g_EntityClassDoom3_bad ) ;
GlobalFileSystem ( ) . detach ( g_EntityClassDoom3 ) ;
}
class EntityClassDoom3Dependencies : public GlobalFileSystemModuleRef , public GlobalShaderCacheModuleRef
{
} ;
class EntityClassDoom3API
{
EntityClassManager m_eclassmanager ;
public :
typedef EntityClassManager Type ;
STRING_CONSTANT ( Name , " doom3 " ) ;
EntityClassDoom3API ( )
{
EntityClassDoom3_construct ( ) ;
m_eclassmanager . findOrInsert = & EntityClassDoom3_findOrInsert ;
m_eclassmanager . findListType = & EntityClassDoom3_findListType ;
m_eclassmanager . forEach = & EntityClassDoom3_forEach ;
m_eclassmanager . attach = & EntityClassDoom3_attach ;
m_eclassmanager . detach = & EntityClassDoom3_detach ;
m_eclassmanager . realise = & EntityClassDoom3_realise ;
m_eclassmanager . unrealise = & EntityClassDoom3_unrealise ;
}
~ EntityClassDoom3API ( )
{
EntityClassDoom3_destroy ( ) ;
}
EntityClassManager * getTable ( )
{
return & m_eclassmanager ;
}
} ;
# include "modulesystem/singletonmodule.h"
# include "modulesystem/moduleregistry.h"
typedef SingletonModule < EntityClassDoom3API , EntityClassDoom3Dependencies > EntityClassDoom3Module ;
typedef Static < EntityClassDoom3Module > StaticEntityClassDoom3Module ;
StaticRegisterModule staticRegisterEntityClassDoom3 ( StaticEntityClassDoom3Module : : instance ( ) ) ;