2 BobToolz plugin for GtkRadiant
3 Copyright (C) 2001 Gordon Biggans
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // DEntity.cpp: implementation of the DEntity class.
22 //////////////////////////////////////////////////////////////////////
27 #pragma warning(disable : 4786)
32 #include "dialogs/dialogs-gtk.h"
36 const char* brushEntityList[] = {
56 //////////////////////////////////////////////////////////////////////
57 // Construction/Destruction
58 //////////////////////////////////////////////////////////////////////
60 DEntity::DEntity( char *classname, int ID ){
61 SetClassname( classname );
72 //////////////////////////////////////////////////////////////////////
74 //////////////////////////////////////////////////////////////////////
76 void DEntity::ClearBrushes(){
77 for ( list<DBrush *>::const_iterator deadBrush = brushList.begin(); deadBrush != brushList.end(); deadBrush++ )
84 void DEntity::ClearPatches(){
85 for ( list<DPatch *>::const_iterator deadPatch = patchList.begin(); deadPatch != patchList.end(); deadPatch++ )
92 DPatch* DEntity::NewPatch(){
93 DPatch* newPatch = new DPatch;
95 patchList.push_back( newPatch );
100 DBrush* DEntity::NewBrush( int ID ){
101 DBrush* newBrush = new DBrush( ID );
103 brushList.push_back( newBrush );
108 char* getNextBracket( char* s ){
121 bool DEntity::LoadFromPrt( char *filename ){
123 strcpy( portals.fn, filename );
126 if ( portals.node_count == 0 ) {
134 for ( unsigned int i = 0; i < portals.node_count; i++ )
137 DBrush* brush = NewBrush();
139 for ( unsigned int j = 0; j < portals.node[i].portal_count; j++ )
141 for ( unsigned int k = 0; k < portals.node[i].portal[j].point_count - 2; k++ )
143 vec3_t v1, v2, normal, n;
144 VectorSubtract( portals.node[i].portal[j].point[k + 2].p, portals.node[i].portal[j].point[k + 1].p, v1 );
145 VectorSubtract( portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k + 1].p, v2 );
146 CrossProduct( v1, v2, n );
147 VectorNormalize( n, v2 );
150 VectorCopy( v2, normal );
154 VectorSubtract( v2, normal, v1 );
155 if ( VectorLength( v1 ) > 0.01 ) {
163 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 );
166 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 );
170 brush->BuildInRadiant( FALSE, NULL );
177 DPlane* DEntity::AddFaceToBrush( vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID ){
178 DBrush* buildBrush = GetBrushForID( ID );
179 return buildBrush->AddFace( va, vb, vc, faceData );
180 // slow, dont use much
183 DBrush* DEntity::GetBrushForID( int ID ){
184 DBrush* buildBrush = NULL;
186 for ( list<DBrush *>::const_iterator chkBrush = brushList.begin(); chkBrush != brushList.end(); chkBrush++ )
188 if ( ( *chkBrush )->m_nBrushID == ID ) {
189 buildBrush = ( *chkBrush );
195 buildBrush = NewBrush( ID );
201 void DEntity::LoadSelectedBrushes(){
205 int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles();
207 for ( int i = 0; i < count; i++ ) {
208 brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle( i );
210 if ( brush->pPatch ) {
214 DBrush* loadBrush = NewBrush( i );
215 loadBrush->LoadFromBrush_t( brush, TRUE );
218 g_FuncTable.m_pfnReleaseSelectedBrushHandles();
221 void DEntity::LoadSelectedPatches(){
225 int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles();
227 for ( int i = 0; i < count; i++ )
229 //$ FIXME: m_pfnGetPatchHandle
230 patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData( i );
232 DPatch* loadPatch = NewPatch();
233 loadPatch->LoadFromBrush_t( pmesh->pSymbiot );
236 g_FuncTable.m_pfnReleasePatchHandles();
239 bool* DEntity::BuildIntersectList(){
240 int max = GetIDMax();
245 bool* pbIntList = new bool[max];
246 memset( pbIntList, 0, sizeof( bool ) * ( max ) );
248 for ( list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
250 list<DBrush *>::const_iterator pB2 = pB1;
251 for ( pB2++; pB2 != brushList.end(); pB2++ )
253 if ( ( *pB1 )->IntersectsWith( ( *pB2 ) ) ) {
254 pbIntList[( *pB1 )->m_nBrushID] = TRUE;
255 pbIntList[( *pB2 )->m_nBrushID] = TRUE;
263 bool* DEntity::BuildDuplicateList(){
264 int max = GetIDMax();
269 bool* pbDupList = new bool[max];
270 memset( pbDupList, 0, sizeof( bool ) * ( max ) );
272 for ( list<DBrush *>::const_iterator pB1 = brushList.begin(); pB1 != brushList.end(); pB1++ )
274 list<DBrush *>::const_iterator pB2 = pB1;
275 for ( pB2++; pB2 != brushList.end(); pB2++ )
277 if ( **pB1 == *pB2 ) {
278 pbDupList[( *pB1 )->m_nBrushID] = TRUE;
279 pbDupList[( *pB2 )->m_nBrushID] = TRUE;
287 void DEntity::SelectBrushes( bool *selectList ){
288 if ( selectList == NULL ) {
292 g_FuncTable.m_pfnDeselectAllBrushes();
294 g_FuncTable.m_pfnAllocateActiveBrushHandles();
296 for ( list<DBrush *>::const_iterator pBrush = brushList.begin(); pBrush != brushList.end(); pBrush++ )
298 if ( selectList[( *pBrush )->m_nBrushID] ) {
299 g_FuncTable.m_pfnSelectBrush( ( *pBrush )->QER_brush );
302 g_FuncTable.m_pfnReleaseActiveBrushHandles();
305 bool DEntity::LoadFromEntity( int id, bool bLoadPatches ) {
306 return LoadFromEntity( (entity_t*)g_FuncTable.m_pfnGetEntityHandle( id ), bLoadPatches );
309 bool DEntity::LoadFromEntity( entity_t* ent, bool bLoadPatches ) {
316 epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList( QER_Entity );
317 LoadEPairList( epl );
321 for ( i = 0; brushEntityList[i]; i++ )
323 if ( !stricmp( brushEntityList[i], m_Classname ) ) {
333 int count = g_FuncTable.m_pfnAllocateEntityBrushHandles( QER_Entity );
335 for ( i = 0; i < count; i++ )
338 brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle( i );
340 if ( brush == NULL ) {
341 DoMessageBox( "GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK );
345 if ( brush->pPatch ) {
346 if ( bLoadPatches ) {
347 DPatch* loadPatch = NewPatch();
348 loadPatch->LoadFromBrush_t( brush );
353 DBrush* loadBrush = NewBrush( i );
354 loadBrush->LoadFromBrush_t( brush, TRUE );
358 g_FuncTable.m_pfnReleaseEntityBrushHandles();
363 void DEntity::RemoveNonCheckBrushes( list<Str>* exclusionList, bool useDetail ){
364 list<DBrush *>::iterator chkBrush = brushList.begin();
366 while ( chkBrush != brushList.end() )
369 if ( ( *chkBrush )->IsDetail() ) {
371 chkBrush = brushList.erase( chkBrush );
376 list<Str>::iterator eTexture;
378 for ( eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++ )
380 if ( ( *chkBrush )->HasTexture( ( *eTexture ).GetBuffer() ) ) {
382 chkBrush = brushList.erase( chkBrush );
387 if ( eTexture == exclusionList->end() ) {
393 void DEntity::ResetChecks( list<Str>* exclusionList ){
394 for ( list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
396 ( *resetBrush )->ResetChecks( exclusionList );
400 int DEntity::FixBrushes( bool rebuild ){
401 g_FuncTable.m_pfnAllocateActiveBrushHandles();
405 for ( list<DBrush *>::const_iterator fixBrush = brushList.begin(); fixBrush != brushList.end(); fixBrush++ )
407 int count = ( *fixBrush )->RemoveRedundantPlanes();
411 g_FuncTable.m_pfnDeleteBrushHandle( ( *fixBrush )->QER_brush );
413 ( *fixBrush )->BuildInRadiant( FALSE, NULL );
418 g_FuncTable.m_pfnReleaseActiveBrushHandles();
423 void DEntity::BuildInRadiant( bool allowDestruction ){
424 bool makeEntity = strcmp( m_Classname, "worldspawn" ) ? true : false;
427 entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle();
429 epair_t* pEpS = GetNextChainItem( NULL, "classname", m_Classname );
433 for ( list<DEPair* >::const_iterator buildEPair = epairList.begin(); buildEPair != epairList.end(); buildEPair++ )
435 pEp = GetNextChainItem( pEp, ( *buildEPair )->key, ( *buildEPair )->value );
438 g_EntityTable.m_pfnSetEntityKeyValList( pE, pEpS );
440 g_FuncTable.m_pfnCommitEntityHandleToMap( pE );
442 for ( list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
443 ( *buildBrush )->BuildInRadiant( allowDestruction, NULL, pE );
445 for ( list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
446 ( *buildPatch )->BuildInRadiant( pE );
452 for ( list<DBrush *>::const_iterator buildBrush = brushList.begin(); buildBrush != brushList.end(); buildBrush++ )
453 ( *buildBrush )->BuildInRadiant( allowDestruction, NULL );
455 for ( list<DPatch *>::const_iterator buildPatch = patchList.begin(); buildPatch != patchList.end(); buildPatch++ )
456 ( *buildPatch )->BuildInRadiant();
462 int DEntity::GetIDMax( void ) {
464 for ( list<DBrush *>::const_iterator cntBrush = brushList.begin(); cntBrush != brushList.end(); cntBrush++ ) {
465 if ( ( *cntBrush )->m_nBrushID > max ) {
466 max = ( *cntBrush )->m_nBrushID;
472 void DEntity::SetClassname( char *classname ) {
473 m_Classname = classname;
476 void DEntity::SaveToFile( FILE *pFile ){
477 fprintf( pFile, "{\n" );
479 fprintf( pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname );
481 for ( list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
483 fprintf( pFile, "\"%s\" \"%s\"\n", (const char *)( *ep )->key, (const char *)( *ep )->value );
486 for ( list<DBrush *>::const_iterator bp = brushList.begin(); bp != brushList.end(); bp++ )
488 ( *bp )->SaveToFile( pFile );
491 fprintf( pFile, "}\n" );
494 void DEntity::ClearEPairs(){
495 for ( list<DEPair *>::const_iterator deadEPair = epairList.begin(); deadEPair != epairList.end(); deadEPair++ )
497 delete ( *deadEPair );
502 void DEntity::AddEPair( const char *key, const char *value ) {
504 newEPair = FindEPairByKey( key );
506 newEPair = new DEPair;
507 newEPair->Build( key, value );
508 epairList.push_back( newEPair );
511 newEPair->Build( key, value );
515 void DEntity::LoadEPairList( epair_t *epl ){
519 if ( !strcmp( ep->key, "classname" ) ) {
520 SetClassname( ep->value );
523 AddEPair( ep->key, ep->value );
530 bool DEntity::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName,
531 int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild ){
532 g_FuncTable.m_pfnDeselectAllBrushes();
534 g_FuncTable.m_pfnAllocateActiveBrushHandles();
538 for ( list<DBrush *>::const_iterator resetBrush = brushList.begin(); resetBrush != brushList.end(); resetBrush++ )
540 bool tmp = ( *resetBrush )->ResetTextures( textureName, fScale, fShift, rotation, newTextureName,
541 bResetTextureName, bResetScale, bResetShift, bResetRotation );
547 entity_t *pE = ( *resetBrush )->QER_brush->owner;
548 g_FuncTable.m_pfnDeleteBrushHandle( ( *resetBrush )->QER_brush );
549 ( *resetBrush )->BuildInRadiant( FALSE, NULL, pE->entityId == 0 ? NULL : pE );
551 if ( pE->entityId == 0 ? NULL : pE ) {
557 if ( bResetTextureName ) {
558 for ( list<DPatch *>::const_iterator resetPatch = patchList.begin(); resetPatch != patchList.end(); resetPatch++ )
560 bool tmp = ( *resetPatch )->ResetTextures( textureName, newTextureName );
566 entity_t *pE = ( *resetPatch )->QER_brush->owner;
567 g_FuncTable.m_pfnDeleteBrushHandle( ( *resetPatch )->QER_brush );
568 ( *resetPatch )->BuildInRadiant( pE->entityId == 0 ? NULL : pE );
574 g_FuncTable.m_pfnReleaseActiveBrushHandles();
579 DEPair* DEntity::FindEPairByKey( const char* keyname ){
580 for ( list<DEPair *>::const_iterator ep = epairList.begin(); ep != epairList.end(); ep++ )
582 char* c = ( *ep )->key;
583 if ( !strcmp( c, keyname ) ) {
590 void DEntity::RemoveFromRadiant(){
591 g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity );
596 void DEntity::SpawnString( const char* key, const char* defaultstring, const char** out ){
597 DEPair* pEP = FindEPairByKey( key );
602 *out = defaultstring;
606 void DEntity::SpawnInt( const char* key, const char* defaultstring, int* out ){
607 DEPair* pEP = FindEPairByKey( key );
609 *out = atoi( pEP->value );
612 *out = atoi( defaultstring );
616 void DEntity::SpawnFloat( const char* key, const char* defaultstring, float* out ){
617 DEPair* pEP = FindEPairByKey( key );
619 *out = static_cast< float >( atof( pEP->value ) );
622 *out = static_cast< float >( atof( defaultstring ) );
626 void DEntity::SpawnVector( const char* key, const char* defaultstring, vec_t* out ){
627 DEPair* pEP = FindEPairByKey( key );
629 sscanf( pEP->value, "%f %f %f", &out[0], &out[1], &out[2] );
632 sscanf( defaultstring, "%f %f %f", &out[0], &out[1], &out[2] );
636 int DEntity::GetBrushCount( void ) {
637 return brushList.size();
640 DBrush* DEntity::FindBrushByPointer( brush_t* brush ) {
641 for ( list<DBrush *>::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++ ) {
642 DBrush* pBrush = ( *listBrush );
643 if ( pBrush->QER_brush == brush ) {