gtkradiant/radiant/eclass_def.cpp
spog d584d94549 added string-pooling for shader variable names and entity keys
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@26 8a3a26a2-13c4-0310-b231-cf6edde360e5
2006-02-26 22:27:38 +00:00

407 lines
7.8 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 <stdlib.h>
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 <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->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<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;
}
}
}