auto str = StringOutputStream()(bla) use form was not doing copy elision or move, but copy
386 lines
7.9 KiB
C++
386 lines
7.9 KiB
C++
/*
|
|
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<EclassDefAPI, EntityClassDefDependencies> EclassDefModule;
|
|
typedef Static<EclassDefModule> StaticEclassDefModule;
|
|
StaticRegisterModule staticRegisterEclassDef( StaticEclassDefModule::instance() );
|
|
|
|
|
|
#include "string/string.h"
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
char com_token[1024];
|
|
|
|
/*
|
|
==============
|
|
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 ) {
|
|
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 <classname> (0 0 0) ?
|
|
/ *QUAKED <classname> (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->name_set( 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++;
|
|
}
|
|
}
|
|
|
|
StringRange parms( text, text );
|
|
{ // get the flags: advance to the first \n
|
|
while ( *text && *text++ != '\n' ){};
|
|
parms = { parms.begin(), text };
|
|
}
|
|
|
|
{
|
|
// any remaining words are parm flags
|
|
const char* p = parms.begin();
|
|
for ( std::size_t i = 0; i < MAX_FLAGS; i++ )
|
|
{
|
|
p = COM_Parse( p );
|
|
if ( p == nullptr || p > parms.end() ) {
|
|
break;
|
|
}
|
|
if( string_equal( Get_COM_Token(), "-" )
|
|
|| string_equal( Get_COM_Token(), "x" )
|
|
|| string_equal_prefix_nocase( Get_COM_Token(), "unused" ) ){
|
|
continue;
|
|
}
|
|
strncpy( e->flagnames[i], Get_COM_Token(), std::size( e->flagnames[i] ) - 1 );
|
|
}
|
|
}
|
|
|
|
e->m_comments = text;
|
|
|
|
setSpecialLoad( e, "model=", e->m_modelpath );
|
|
e->m_modelpath = StringStream<64>( PathCleaned( e->m_modelpath.c_str() ) );
|
|
|
|
if ( !e->fixedsize ) {
|
|
EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction" ) );
|
|
}
|
|
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<TextFileInputStream> 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;
|
|
}
|
|
}
|
|
}
|