/*
===========================================================================
Doom 3 GPL Source Code
Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
Doom 3 Source Code 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 3 of the License, or
(at your option) any later version.
Doom 3 Source Code 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 Doom 3 Source Code. If not, see .
In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "qe3.h"
#include "io.h"
#include "../../renderer/tr_local.h"
struct evarPrefix_t {
int type;
const char *prefix;
};
const evarPrefix_t EvarPrefixes[] = {
{ EVAR_STRING, "editor_var " },
{ EVAR_INT, "editor_int " },
{ EVAR_FLOAT, "editor_float " },
{ EVAR_BOOL, "editor_bool " },
{ EVAR_COLOR, "editor_color " },
{ EVAR_MATERIAL,"editor_mat " },
{ EVAR_MODEL, "editor_model " },
{ EVAR_GUI, "editor_gui " },
{ EVAR_SOUND, "editor_snd "}
};
const int NumEvarPrefixes = sizeof(EvarPrefixes) / sizeof(evarPrefix_t);
eclass_t *eclass = NULL;
eclass_t *eclass_bad = NULL;
char eclass_directory[1024];
// md3 cache for misc_models
eclass_t *g_md3Cache = NULL;
/*
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
*/
void CleanEntityList( eclass_t *&pList ) {
while (pList) {
eclass_t* pTemp = pList->next;
delete pList;
pList = pTemp;
}
pList = NULL;
}
void CleanUpEntities()
{
CleanEntityList(eclass);
CleanEntityList(g_md3Cache);
if ( eclass_bad ) {
delete eclass_bad;
eclass_bad = NULL;
}
}
void ExtendBounds(idVec3 v, idVec3 &vMin, idVec3 &vMax)
{
for (int i = 0 ;i < 3 ;i++)
{
float f = v[i];
if (f < vMin[i])
{
vMin[i] = f;
}
if (f > vMax[i])
{
vMax[i] = f;
}
}
}
bool LoadModel(const char *pLocation, eclass_t *e, idVec3 &vMin, idVec3 &vMax, const char *pSkin)
{
vMin[0] = vMin[1] = vMin[2] = 999999;
vMax[0] = vMax[1] = vMax[2] = -999999;
if (strstr(pLocation, ".ase") != NULL) // FIXME: not correct!
{
idBounds b;
e->modelHandle = renderModelManager->FindModel( pLocation );
b = e->modelHandle->Bounds( NULL );
VectorCopy(b[0], vMin);
VectorCopy(b[1], vMax);
return true;
}
return false;
}
eclass_t *EClass_Alloc( void ) {
eclass_t *e;
e = new eclass_t;
if ( e == NULL ) {
return NULL;
}
e->fixedsize = false;
e->unknown = false;
e->mins.Zero();
e->maxs.Zero();
e->color.Zero();
memset( &e->texdef, 0, sizeof( e->texdef ) );
e->modelHandle = NULL;
e->entityModel = NULL;
e->nFrame = 0;
e->nShowFlags = 0;
e->hPlug = 0;
e->next = NULL;
return e;
}
eclass_t *EClass_InitFromDict( const idDict *d, const char *name ) {
eclass_t *e;
const idKeyValue *kv;
// only include entityDefs with "editor_" values in them
if ( !d->MatchPrefix( "editor_" ) ) {
return NULL;
}
e = EClass_Alloc();
if ( !e ) {
return NULL;
}
e->defArgs = *d;
idStr str;
idStr text;
idStr varname;
idStr defaultStr;
e->name = name;
d->GetVector("editor_color", "0 0 1", e->color);
d->GetString("editor_mins", "", str);
if (str != "?") {
d->GetVector("editor_mins", "0 0 0", e->mins);
d->GetVector("editor_maxs", "0 0 0", e->maxs);
e->fixedsize = true;
} else {
e->fixedsize = false;
}
d->GetString("editor_material", "", e->defMaterial);
//str = d->GetString("model");
//if (str.Length()) {
// e->entityModel = renderModelManager->FindModel(str);
//}
str = "";
// concatenate all editor usage comments
text = "";
kv = d->MatchPrefix( "editor_usage" );
while( kv != NULL ) {
text += kv->GetValue();
if ( !kv->GetValue().Length() || ( text[ text.Length() - 1 ] != '\n' ) ) {
text += "\n";
}
kv = d->MatchPrefix( "editor_usage", kv );
}
e->desc = text;
str += "Spawn args:\n";
for (int i = 0; i < NumEvarPrefixes; i++) {
kv = d->MatchPrefix(EvarPrefixes[i].prefix);
while (kv) {
evar_t ev;
kv->GetKey().Right( kv->GetKey().Length() - strlen(EvarPrefixes[i].prefix), ev.name );
ev.desc = kv->GetValue();
ev.type = EvarPrefixes[i].type;
e->vars.Append(ev);
kv = d->MatchPrefix(EvarPrefixes[i].prefix, kv);
}
}
/*
while( kv != NULL ) {
kv->key.Right( kv->key.Length() - 11, varname );
str += va( "'%s':\t %s", varname.c_str(), kv->value.c_str() );
if ( d->GetString( varname, "", defaultStr ) && defaultStr.Length() ) {
str += va( " Default '%s'.", defaultStr.c_str() );
}
str += "\n";
kv = d->MatchPrefix( "editor_var ", kv );
}
e->comments = Mem_CopyString( str.c_str() );
*/
// concatenate all variable comments
kv = d->MatchPrefix( "editor_copy" );
while (kv) {
const char *temp = d->GetString(kv->GetValue());
if (temp && *temp) {
e->args.Set(kv->GetValue(), d->GetString(kv->GetValue()));
}
kv = d->MatchPrefix("editor_copy", kv);
}
// setup show flags
e->nShowFlags = 0;
if (d->GetBool("editor_rotatable")) {
e->nShowFlags |= ECLASS_ROTATABLE;
}
if (d->GetBool("editor_showangle")) {
e->nShowFlags |= ECLASS_ANGLE;
}
if (d->GetBool("editor_mover")) {
e->nShowFlags |= ECLASS_MOVER;
}
if (d->GetBool("editor_env") || idStr::Icmpn(e->name, "env_", 4) == 0) {
e->nShowFlags |= (ECLASS_ENV | ECLASS_ROTATABLE);
if (d->GetBool("editor_ragdoll")) {
e->defArgs.Set("model", "");
}
}
if (d->GetBool("editor_combatnode")) {
e->nShowFlags |= ECLASS_COMBATNODE;
}
if (d->GetBool("editor_light")) {
e->nShowFlags |= ECLASS_LIGHT;
}
if ( idStr::Icmp(e->name, "light") == 0 ) {
e->nShowFlags |= ECLASS_LIGHT;
} else if ( idStr::Icmp(e->name, "path") == 0 ) {
e->nShowFlags |= ECLASS_PATH;
} else if ( idStr::Icmp(e->name, "target_null") == 0 ) {
e->nShowFlags |= ECLASS_CAMERAVIEW;
} else if ( idStr::Icmp(e->name, "worldspawn") == 0 ) {
e->nShowFlags |= ECLASS_WORLDSPAWN;
} else if ( idStr::Icmp(e->name, "speaker") == 0 ) {
e->nShowFlags |= ECLASS_SPEAKER;
} else if ( idStr::Icmp( e->name, "func_emitter" ) == 0 || idStr::Icmp( e->name, "func_splat" ) == 0 ) {
e->nShowFlags |= ECLASS_PARTICLE;
} else if ( idStr::Icmp(e->name, "func_liquid") == 0 ) {
e->nShowFlags |= ECLASS_LIQUID;
}
return e;
}
void EClass_InsertSortedList(eclass_t *&pList, eclass_t *e)
{
eclass_t *s;
if (!pList)
{
pList = e;
return;
}
s = pList;
if (stricmp (e->name, s->name) < 0)
{
e->next = s;
pList = e;
return;
}
do
{
if (!s->next || stricmp (e->name, s->next->name) < 0)
{
e->next = s->next;
s->next = e;
return;
}
s=s->next;
} while (1);
}
/*
=================
Eclass_InsertAlphabetized
=================
*/
void Eclass_InsertAlphabetized (eclass_t *e)
{
#if 1
EClass_InsertSortedList(eclass, e);
#else
eclass_t *s;
if (!eclass)
{
eclass = e;
return;
}
s = eclass;
if (stricmp (e->name, s->name) < 0)
{
e->next = s;
eclass = e;
return;
}
do
{
if (!s->next || stricmp (e->name, s->next->name) < 0)
{
e->next = s->next;
s->next = e;
return;
}
s=s->next;
} while (1);
#endif
}
void Eclass_InitForSourceDirectory (const char *path)
{
int c = declManager->GetNumDecls(DECL_ENTITYDEF);
for (int i = 0; i < c; i++) {
const idDeclEntityDef *def = static_cast( declManager->DeclByIndex( DECL_ENTITYDEF, i ) );
if ( def ) {
eclass_t *e = EClass_InitFromDict( &def->dict, def->GetName() );
if ( e ) {
Eclass_InsertAlphabetized (e);
}
}
}
eclass_bad = EClass_Alloc();
if ( !eclass_bad ) {
return;
}
eclass_bad->color.x = 0.0f;
eclass_bad->color.y = 0.5f;
eclass_bad->color.z = 0.0f;
eclass_bad->fixedsize = false;
eclass_bad->name = Mem_CopyString( "UKNOWN ENTITY CLASS" );
}
eclass_t *Eclass_ForName (const char *name, bool has_brushes)
{
eclass_t *e;
char buff[1024];
if (!name) {
return eclass_bad;
}
for ( e = eclass; e; e = e->next ) {
if ( !strcmp( name, e->name ) ) {
return e;
}
}
e = EClass_Alloc();
if ( !e ) {
return NULL;
}
e->name = Mem_CopyString( name );
sprintf(buff, "%s not found in def/*.def\n", name);
e->comments = Mem_CopyString( buff );
e->color.x = 0.0f;
e->color.y = 0.5f;
e->color.z = 0.0f;
e->fixedsize = !has_brushes;
e->mins.x = e->mins.y = e->mins.z = -8.0f;
e->maxs.x = e->maxs.y = e->maxs.z = 8.0f;
Eclass_InsertAlphabetized( e );
return e;
}
eclass_t* GetCachedModel(entity_t *pEntity, const char *pName, idVec3 &vMin, idVec3 &vMax)
{
eclass_t *e = NULL;
if (pName == NULL || strlen(pName) == 0) {
return NULL;
}
for (e = g_md3Cache; e ; e = e->next) {
if (!strcmp (pName, e->name)) {
pEntity->md3Class = e;
VectorCopy(e->mins, vMin);
VectorCopy(e->maxs, vMax);
return e;
}
}
e = (eclass_t*)Mem_ClearedAlloc(sizeof(*e));
memset (e, 0, sizeof(*e));
e->name = Mem_CopyString( pName );
e->color[0] = e->color[2] = 0.85f;
if (LoadModel(pName, e, vMin, vMax, NULL)) {
EClass_InsertSortedList(g_md3Cache, e);
VectorCopy(vMin, e->mins);
VectorCopy(vMax, e->maxs);
pEntity->md3Class = e;
return e;
}
return NULL;
}