gtkradiant/contrib/bobtoolz/DEntity.cpp

676 lines
15 KiB
C++

/*
BobToolz plugin for GtkRadiant
Copyright (C) 2001 Gordon Biggans
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// DEntity.cpp: implementation of the DEntity class.
//
//////////////////////////////////////////////////////////////////////
#include "StdAfx.h"
#ifdef _WIN32
#pragma warning(disable : 4786)
#endif
#include "DEntity.h"
#include "dialogs-gtk.h"
#include "misc.h"
#include "CPortals.h"
const char* brushEntityList[] = {
"worldspawn",
"trigger_always",
"trigger_hurt",
"trigger_multiple",
"trigger_push",
"trigger_teleport",
"func_bobbing",
"func_button",
"func_door",
"func_group",
"func_pendulum",
"func_plat",
"func_rotating",
"func_static",
"func_timer",
"func_train",
0
};
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
DEntity::DEntity(char *classname, int ID)
{
SetClassname(classname);
m_nID = ID;
QER_Entity = NULL;
}
DEntity::~DEntity()
{
ClearPatches();
ClearBrushes();
ClearEPairs();
}
//////////////////////////////////////////////////////////////////////
// Implementation
//////////////////////////////////////////////////////////////////////
void DEntity::ClearBrushes()
{
for(list<DBrush *>::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++)
{
delete *deadBrush;
}
brushList.clear();
}
void DEntity::ClearPatches()
{
for(list<DPatch *>::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++)
{
delete *deadPatch;
}
patchList.clear();
}
DPatch* DEntity::NewPatch()
{
DPatch* newPatch = new DPatch;
patchList.push_back(newPatch);
return newPatch;
}
DBrush* DEntity::NewBrush(int ID)
{
DBrush* newBrush = new DBrush(ID);
brushList.push_back(newBrush);
return newBrush;
}
char* getNextBracket(char* s)
{
char* p = s;
while(*p)
{
p++;
if(*p == '(')
break;
}
return p;
}
bool DEntity::LoadFromPrt(char *filename)
{
CPortals portals;
strcpy(portals.fn, filename);
portals.Load();
if(portals.node_count == 0)
return FALSE;
ClearBrushes();
ClearEPairs();
bool build = false;
for(unsigned int i = 0; i < portals.node_count; i++)
{
build = false;
DBrush* brush = NewBrush();
for(unsigned int j = 0; j < portals.node[i].portal_count; j++)
{
for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++)
{
vec3_t v1, v2, normal, n;
VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1);
VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2);
CrossProduct(v1, v2, n);
VectorNormalize(n, v2);
if(k == 0)
{
VectorCopy(v2, normal);
}
else
{
VectorSubtract(v2, normal, v1);
if(VectorLength(v1) > 0.01)
{
build = true;
break;
}
}
}
if(!build)
brush->AddFace(portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[0].p, "textures/common/caulk", FALSE);
else
brush->AddFace(portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[2].p, "textures/common/caulk", FALSE);
}
if(build)
brush->BuildInRadiant(FALSE, NULL);
}
return TRUE;
}
DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID)
{
DBrush* buildBrush = GetBrushForID(ID);
return buildBrush->AddFace(va, vb, vc, faceData);
// slow, dont use much
}
DBrush* DEntity::GetBrushForID(int ID)
{
DBrush* buildBrush = NULL;
for(list<DBrush *>::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++)
{
if((*chkBrush)->m_nBrushID == ID)
{
buildBrush = (*chkBrush);
break;
}
}
if(!buildBrush)
buildBrush = NewBrush(ID);
return buildBrush;
}
void DEntity::LoadSelectedBrushes()
{
ClearBrushes();
ClearEPairs();
int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
for(int i = 0; i < count; i++) {
brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i);
if(brush->pPatch)
continue;
DBrush* loadBrush = NewBrush(i);
loadBrush->LoadFromBrush_t(brush, TRUE);
}
g_FuncTable.m_pfnReleaseSelectedBrushHandles();
}
void DEntity::LoadSelectedPatches()
{
ClearPatches();
ClearEPairs();
int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();
for(int i = 0; i < count; i++)
{
//$ FIXME: m_pfnGetPatchHandle
patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i);
DPatch* loadPatch = NewPatch();
loadPatch->LoadFromBrush_t(pmesh->pSymbiot);
}
g_FuncTable.m_pfnReleasePatchHandles();
}
bool* DEntity::BuildIntersectList()
{
int max = GetIDMax();
if(max == 0)
return NULL;
bool* pbIntList = new bool[max];
memset(pbIntList, 0, sizeof(bool)*(max));
for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
{
list<DBrush *>::const_iterator pB2=pB1;
for(pB2++; pB2!=brushList.end(); pB2++)
{
if((*pB1)->IntersectsWith((*pB2)))
{
pbIntList[(*pB1)->m_nBrushID] = TRUE;
pbIntList[(*pB2)->m_nBrushID] = TRUE;
}
}
}
return pbIntList;
}
bool* DEntity::BuildDuplicateList()
{
int max = GetIDMax();
if(max == 0)
return NULL;
bool* pbDupList = new bool[max];
memset(pbDupList, 0, sizeof(bool)*(max));
for(list<DBrush *>::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++)
{
list<DBrush *>::const_iterator pB2=pB1;
for(pB2++; pB2!=brushList.end(); pB2++)
{
if(**pB1 == *pB2)
{
pbDupList[(*pB1)->m_nBrushID] = TRUE;
pbDupList[(*pB2)->m_nBrushID] = TRUE;
}
}
}
return pbDupList;
}
void DEntity::SelectBrushes(bool *selectList)
{
if(selectList == NULL)
return;
g_FuncTable.m_pfnDeselectAllBrushes();
g_FuncTable.m_pfnAllocateActiveBrushHandles();
for(std::list<DBrush *>::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++)
{
if(selectList[(*pBrush)->m_nBrushID])
g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush);
}
g_FuncTable.m_pfnReleaseActiveBrushHandles();
}
bool DEntity::LoadFromEntity(int id, bool bLoadPatches) {
return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches);
}
bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) {
ClearPatches();
ClearBrushes();
ClearEPairs();
QER_Entity = ent;
epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity);
LoadEPairList(epl);
bool keep = FALSE;
int i;
for(i = 0; brushEntityList[i]; i++)
{
if(!stricmp(brushEntityList[i], m_Classname))
{
keep = TRUE;
break;
}
}
if(!keep)
return FALSE;
int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity);
for(i = 0; i < count; i++)
{
brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i);
if(brush == NULL) {
DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK);
continue;
}
if(brush->pPatch)
{
if(bLoadPatches)
{
DPatch* loadPatch = NewPatch();
loadPatch->LoadFromBrush_t(brush);
}
}
else
{
DBrush* loadBrush = NewBrush(i);
loadBrush->LoadFromBrush_t(brush, TRUE);
}
}
g_FuncTable.m_pfnReleaseEntityBrushHandles();
return TRUE;
}
void DEntity::RemoveNonCheckBrushes(list<Str>* exclusionList, bool useDetail)
{
list<DBrush *>::iterator chkBrush=brushList.begin();
while( chkBrush!=brushList.end() )
{
if(!useDetail)
{
if((*chkBrush)->IsDetail())
{
delete *chkBrush;
chkBrush = brushList.erase(chkBrush);
continue;
}
}
list<Str>::iterator eTexture;
for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ )
{
if((*chkBrush)->HasTexture((*eTexture).GetBuffer()))
{
delete *chkBrush;
chkBrush = brushList.erase(chkBrush);
break;
}
}
if( eTexture == exclusionList->end() )
chkBrush++;
}
}
void DEntity::ResetChecks(list<Str>* exclusionList)
{
for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
{
(*resetBrush)->ResetChecks(exclusionList);
}
}
int DEntity::FixBrushes(bool rebuild)
{
g_FuncTable.m_pfnAllocateActiveBrushHandles();
int cnt = 0;
for(list<DBrush *>::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++)
{
int count = (*fixBrush)->RemoveRedundantPlanes();
if(count)
{
cnt += count;
if(rebuild)
{
g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush);
(*fixBrush)->BuildInRadiant(FALSE, NULL);
}
}
}
g_FuncTable.m_pfnReleaseActiveBrushHandles();
return cnt;
}
void DEntity::BuildInRadiant(bool allowDestruction)
{
bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false;
if(makeEntity)
{
entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();
epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname);
epair_t* pEp = pEpS;
for(list<DEPair* >::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++)
{
pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value);
}
g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS);
g_FuncTable.m_pfnCommitEntityHandleToMap(pE);
for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
(*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE);
for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
(*buildPatch)->BuildInRadiant(pE);
QER_Entity = pE;
}
else
{
for(list<DBrush *>::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++)
(*buildBrush)->BuildInRadiant(allowDestruction, NULL);
for(list<DPatch *>::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++)
(*buildPatch)->BuildInRadiant();
}
}
int DEntity::GetIDMax( void ) {
int max = -1;
for(list<DBrush *>::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) {
if((*cntBrush)->m_nBrushID > max)
max = (*cntBrush)->m_nBrushID;
}
return max+1;
}
void DEntity::SetClassname( char *classname ) {
m_Classname = classname;
}
void DEntity::SaveToFile(FILE *pFile)
{
fprintf(pFile, "{\n");
fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname);
for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
{
fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value);
}
for(list<DBrush *>::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++)
{
(*bp)->SaveToFile(pFile);
}
fprintf(pFile, "}\n");
}
void DEntity::ClearEPairs()
{
for(list<DEPair *>::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++)
{
delete (*deadEPair);
}
epairList.clear();
}
void DEntity::AddEPair(char *key, char *value) {
DEPair* newEPair;
newEPair = FindEPairByKey( key );
if(!newEPair) {
newEPair = new DEPair;
newEPair->Build(key, value);
epairList.push_back(newEPair);
} else {
newEPair->Build(key, value);
}
}
void DEntity::LoadEPairList(epair_t *epl)
{
epair_t* ep = epl;
while(ep)
{
if(!strcmp(ep->key, "classname"))
SetClassname(ep->value);
else
AddEPair(ep->key, ep->value);
ep = ep->next;
}
}
bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild)
{
g_FuncTable.m_pfnDeselectAllBrushes();
g_FuncTable.m_pfnAllocateActiveBrushHandles();
bool reset = FALSE;
for(list<DBrush *>::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++)
{
bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName,
bResetTextureName, bResetScale, bResetShift, bResetRotation);
if(tmp)
{
reset = TRUE;
if(rebuild)
{
entity_t *pE = (*resetBrush)->QER_brush->owner;
g_FuncTable.m_pfnDeleteBrushHandle((*resetBrush)->QER_brush);
(*resetBrush)->BuildInRadiant(FALSE, NULL, pE->entityId == 0 ? NULL : pE);
if( pE->entityId == 0 ? NULL : pE )
{
}
}
}
}
if(bResetTextureName)
{
for(list<DPatch *>::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++)
{
bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName);
if(tmp)
{
reset = TRUE;
if(rebuild)
{
entity_t *pE = (*resetPatch)->QER_brush->owner;
g_FuncTable.m_pfnDeleteBrushHandle((*resetPatch)->QER_brush);
(*resetPatch)->BuildInRadiant(pE->entityId == 0 ? NULL : pE);
}
}
}
}
g_FuncTable.m_pfnReleaseActiveBrushHandles();
return reset;
}
DEPair* DEntity::FindEPairByKey(const char* keyname)
{
for(list<DEPair *>::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++)
{
char* c = (*ep)->key;
if(!strcmp(c, keyname))
return *ep;
}
return NULL;
}
void DEntity::RemoveFromRadiant()
{
g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );
QER_Entity = NULL;
}
void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out)
{
DEPair* pEP = FindEPairByKey(key);
if(pEP) {
*out = pEP->value;
} else {
*out = defaultstring;
}
}
void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out)
{
DEPair* pEP = FindEPairByKey(key);
if(pEP) {
*out = atoi(pEP->value);
} else {
*out = atoi(defaultstring);
}
}
void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out)
{
DEPair* pEP = FindEPairByKey(key);
if(pEP) {
*out = static_cast< float >( atof( pEP->value ) );
} else {
*out = static_cast< float >( atof(defaultstring) );
}
}
void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out)
{
DEPair* pEP = FindEPairByKey(key);
if(pEP) {
sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]);
} else {
sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]);
}
}
int DEntity::GetBrushCount( void ) {
return brushList.size();
}
DBrush* DEntity::FindBrushByPointer( brush_t* brush ) {
for(list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) {
DBrush* pBrush = (*listBrush);
if(pBrush->QER_brush == brush) {
return pBrush;
}
}
return NULL;
}