void Select_Delete( void ) { brush_s* brush; g_ptrSelectedFaces.RemoveAll(); g_ptrSelectedFaceBrushes.RemoveAll(); //selected_face = NULL; clearSelection(); g_qeglobals.d_select_count = 0; g_qeglobals.d_num_move_points = 0; while ( selected_brushes.next != &selected_brushes ) { brush = selected_brushes.next; if ( brush->patchBrush ) { //Patch_Delete(brush->nPatchID); Patch_Delete( brush->pPatch ); } Brush_Free( brush ); } // FIXME: remove any entities with no brushes Sys_UpdateWindows( W_ALL ); }
void CPlugInManager::DeleteBrushHandle(void * vp) { CPtrArray* pHandles[3]; pHandles[0] = &m_SelectedBrushHandles; pHandles[1] = &m_ActiveBrushHandles; pHandles[2] = &m_BrushHandles; for (int j = 0; j < 3; j++) { for (int i = 0; i < pHandles[j]->GetSize(); i++) { brush_t *pb = reinterpret_cast<brush_t*>(pHandles[j]->GetAt(i)); if (pb == reinterpret_cast<brush_t*>(vp)) { if (j == 2) { // only remove it from the list if it is work area // this allows the selected and active list indexes to remain constant // throughout a session (i.e. between an allocate and release) pHandles[j]->RemoveAt(i); } Brush_Free(pb); Sys_MarkMapModified(); // PGM return; } } } }
/* ============= Undo_FreeFirstUndo ============= */ void Undo_FreeFirstUndo(void) { undo_t *undo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity; //remove the oldest undo from the undo buffer undo = g_undolist; g_undolist = g_undolist->next; g_undolist->prev = NULL; // for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) { pNextBrush = pBrush->next; g_undoMemorySize -= Brush_MemorySize(pBrush); Brush_Free(pBrush); } for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) { pNextEntity = pEntity->next; g_undoMemorySize -= Entity_MemorySize(pEntity); Entity_Free(pEntity); } g_undoMemorySize -= sizeof(undo_t); free(undo); g_undoSize--; }
/* ============= Undo_ClearRedo ============= */ void Undo_ClearRedo(void) { undo_t *redo, *nextredo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity; for (redo = g_redolist; redo; redo = nextredo) { nextredo = redo->next; for (pBrush = redo->brushlist.next ; pBrush != NULL && pBrush != &redo->brushlist ; pBrush = pNextBrush) { pNextBrush = pBrush->next; Brush_Free(pBrush); } for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = pNextEntity) { pNextEntity = pEntity->next; Entity_Free(pEntity); } Mem_Free(redo); } g_redolist = NULL; g_lastredo = NULL; g_redoId = 1; }
/* ============= Undo_Clear Clears the undo buffer. ============= */ void Undo_Clear(void) { undo_t *undo, *nextundo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity; Undo_ClearRedo(); for (undo = g_undolist; undo; undo = nextundo) { nextundo = undo->next; for (pBrush = undo->brushlist.next ; pBrush != NULL && pBrush != &undo->brushlist ; pBrush = pNextBrush) { pNextBrush = pBrush->next; g_undoMemorySize -= Brush_MemorySize(pBrush); Brush_Free(pBrush); } for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = pNextEntity) { pNextEntity = pEntity->next; g_undoMemorySize -= Entity_MemorySize(pEntity); Entity_Free(pEntity); } g_undoMemorySize -= sizeof(undo_t); Mem_Free(undo); } g_undolist = NULL; g_lastundo = NULL; g_undoSize = 0; g_undoMemorySize = 0; g_undoId = 1; }
/* ======================================================================================================================= ======================================================================================================================= */ void RemoveRegionBrushes( void ) { int i; if( !region_active ) { return; } for( i = 0; i < 6; i++ ) { Brush_Free( region_sides[i] ); } }
void RemoveRegionBrushes (void) { int i; if (!region_active) return; for (i=0 ; i<4 ; i++) Brush_Free (region_sides[i]); }
/* ================ Map_Free ================ */ void Map_Free (void) { g_bRestoreBetween = false; if (selected_brushes.next && (selected_brushes.next != &selected_brushes) ) { if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES) Map_SaveBetween (); } Texture_ClearInuse (); Pointfile_Clear (); strcpy (currentmap, "unnamed.map"); Sys_SetTitle (currentmap); g_qeglobals.d_num_entities = 0; g_qeglobals.d_numterrapoints = 0; if (!active_brushes.next) { // first map active_brushes.prev = active_brushes.next = &active_brushes; selected_brushes.prev = selected_brushes.next = &selected_brushes; filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; entities.prev = entities.next = &entities; } else { while (active_brushes.next != &active_brushes) Brush_Free (active_brushes.next); while (selected_brushes.next != &selected_brushes) Brush_Free (selected_brushes.next); while (filtered_brushes.next != &filtered_brushes) Brush_Free (filtered_brushes.next); while (entities.next != &entities) Entity_Free (entities.next); } if (world_entity) Entity_Free(world_entity); world_entity = NULL; }
void RemoveRegionBrushes( void ){ int i; if ( !region_active ) { return; } for ( i = 0 ; i < 6 ; i++ ) Brush_Free( region_sides[i] ); CleanFilter( region_startpoint ); Entity_Free( region_startpoint ); }
/* ================ Map_Free free all map elements, reinitialize the structures that depend on them ================ */ void Map_Free( void ){ g_bRestoreBetween = false; if ( selected_brushes.next && ( selected_brushes.next != &selected_brushes ) ) { if ( gtk_MessageBox( g_pParentWnd->m_pWidget, "Copy selection?", " ", MB_YESNO ) == IDYES ) { Map_SaveBetween(); } } QERApp_ActiveShaders_SetInUse( false ); Pointfile_Clear(); g_qeglobals.d_num_entities = 0; if ( !active_brushes.next ) { // first map active_brushes.prev = active_brushes.next = &active_brushes; selected_brushes.prev = selected_brushes.next = &selected_brushes; filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; entities.prev = entities.next = &entities; } else { // free selected faces array g_ptrSelectedFaces.RemoveAll(); g_ptrSelectedFaceBrushes.RemoveAll(); while ( active_brushes.next != &active_brushes ) Brush_Free( active_brushes.next ); while ( selected_brushes.next != &selected_brushes ) Brush_Free( selected_brushes.next ); while ( filtered_brushes.next != &filtered_brushes ) Brush_Free( filtered_brushes.next ); while ( entities.next != &entities ) Entity_Free( entities.next ); } if ( world_entity ) { Entity_Free( world_entity ); } world_entity = NULL; }
/* ======================================================================================================================= Map_Free ======================================================================================================================= */ void Map_Free( void ) { g_bRestoreBetween = false; if( selected_brushes.next && ( selected_brushes.next != &selected_brushes ) ) { if( g_pParentWnd->MessageBox( "Copy selection?", "", MB_YESNO ) == IDYES ) { Map_SaveBetween(); } } // clear all the render and sound system data g_qeglobals.rw->InitFromMap( NULL ); g_qeglobals.sw->ClearAllSoundEmitters(); Texture_ClearInuse(); Pointfile_Clear(); strcpy( currentmap, "unnamed.map" ); Sys_SetTitle( currentmap ); g_qeglobals.d_num_entities = 0; if( !active_brushes.next ) { // first map active_brushes.prev = active_brushes.next = &active_brushes; selected_brushes.prev = selected_brushes.next = &selected_brushes; filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; entities.prev = entities.next = &entities; } else { while( active_brushes.next != &active_brushes ) { Brush_Free( active_brushes.next, false ); } while( selected_brushes.next != &selected_brushes ) { Brush_Free( selected_brushes.next, false ); } while( filtered_brushes.next != &filtered_brushes ) { Brush_Free( filtered_brushes.next, false ); } while( entities.next != &entities ) { Entity_Free( entities.next ); } } if( world_entity ) { Entity_Free( world_entity ); } world_entity = NULL; }
/* ============= Brush_Subtract Returns a list of brushes that remain after B is subtracted from A. May by empty if A is contained inside B. The originals are undisturbed. ============= */ brush_t *Brush_Subtract(brush_t *a, brush_t *b) { // a - b = out (list) brush_t *front, *back; brush_t *in, *out, *next; face_t *f; in = a; out = NULL; for (f = b->brush_faces; f && in; f = f->next) { CSG_SplitBrushByFace(in, f, &front, &back); if (in != a) Brush_Free(in); if (front) { // add to list front->next = out; out = front; } in = back; } //NOTE: in != a just in case brush b has no faces if (in && in != a) { Brush_Free(in); } else { //didn't really intersect for (b = out; b; b = next) { next = b->next; b->next = b->prev = NULL; Brush_Free(b); } return a; } return out; }
/* ======================================================================================================================= Entity_Free Frees the entity and any brushes is has. The entity is removed from the global entities list. ======================================================================================================================= */ void Entity_Free( entity_t *e ) { while ( e->brushes.onext != &e->brushes ) { Brush_Free(e->brushes.onext); } if ( e->next ) { e->next->prev = e->prev; e->prev->next = e->next; } Entity_FreeEpairs( e ); delete e; }
void WINAPI QERApp_DeletePatch(int index) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); patchMesh_t *pPatch = g_pParentWnd->GetPlugInMgr().FindPatchHandle(index); if (pPatch) { brush_t *pb = pPatch->pSymbiot; Patch_Delete( pPatch ); if (pb) Brush_Free( pb ); } #ifdef _DEBUG Sys_Printf("Warning: QERApp_DeletePatch: FindPatchHandle failed\n"); #endif }
/* ======================================================================================================================= ======================================================================================================================= */ void Map_BuildBrushData( void ) { brush_t *b, *next; if( active_brushes.next == NULL ) { return; } Sys_BeginWait(); // this could take a while int n = 0; for( b = active_brushes.next; b != NULL && b != &active_brushes; b = next ) { next = b->next; Brush_Build( b, true, false, false ); if( !b->brush_faces || ( g_PrefsDlg.m_bCleanTiny && CheckForTinyBrush( b, n++, g_PrefsDlg.m_fTinySize ) ) ) { Brush_Free( b ); common->Printf( "Removed degenerate brush\n" ); } } Sys_EndWait(); }
void Map_Read( IDataStream *in, CPtrArray *map ){ entity_t *pEntity; char *buf; unsigned long len = in->GetLength(); buf = new char[len + 1]; in->Read( buf, len ); buf[len] = '\0'; StartTokenParsing( buf ); abortcode = MAP_NOERROR; while ( abortcode == MAP_NOERROR ) { if ( !GetToken( true ) ) { // { or NULL break; } pEntity = Entity_Alloc(); pEntity->pData = new CPtrArray; Entity_Parse( pEntity ); map->Add( pEntity ); } delete [] buf; if ( abortcode != MAP_NOERROR ) { int num_ents, num_brushes,i,j; entity_t *e; CPtrArray *brushes; num_ents = map->GetSize(); for ( i = 0; i < num_ents; i++ ) { e = (entity_t*)map->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); for ( j = 0; j < num_brushes; j++ ) { Brush_Free( (brush_t *)brushes->GetAt( j ), true ); } brushes->RemoveAll(); delete brushes; Entity_Free( e ); } map->RemoveAll(); } }
void CPlugInManager::Cleanup() { int i; for (i = 0; i < m_PlugIns.GetSize(); i++) { CPlugIn *plug = reinterpret_cast<CPlugIn*>(m_PlugIns.GetAt(i)); plug->free(); delete plug; } m_PlugIns.RemoveAll(); for (i = 0; i < m_BrushHandles.GetSize(); i++) { brush_t *pb = reinterpret_cast<brush_t*>(m_BrushHandles.GetAt(i)); Brush_Free(pb); } m_BrushHandles.RemoveAll(); for (i = 0; i < m_EntityHandles.GetSize(); i++) { entity_t *pe = reinterpret_cast<entity_t*>(m_EntityHandles.GetAt(i)); Entity_Free(pe); } m_EntityHandles.RemoveAll(); // patches // these are linked into the map m_PatchesHandles.RemoveAll(); // these patches were allocated by Radiant on plugin request // if the list is not empty, it means either the plugin asked for allocation and never commited them to the map // in which case we are supposed to delete them // or it commited them but never called m_pfnReleasePatchHandles, in case the patches may have already been // erased and we are trying a second time, therefore crashing .. //++timo FIXME: for now I leave a leak warning, we'd need a table to keep track of commited patches #ifdef _DEBUG if (m_PluginPatches.GetSize() != 0) Sys_Printf("WARNING: m_PluginPatches.GetSize() != 0 in CPlugInManager::Cleanup, possible leak\n"); #endif /* for (i = 0; i < m_PluginPatches.GetSize(); i++) { patchMesh_t *pMesh = reinterpret_cast<patchMesh_t*>(m_PluginPatches.GetAt(i)); if (pMesh->pSymbiot) delete pMesh; } m_PluginPatches.RemoveAll(); */ }
/* ============== NewBrushDrag ============== */ void NewBrushDrag (int x, int y) { vec3_t mins, maxs, junk; int i; float temp; brush_t *n; if (!DragDelta (x,y, junk)) return; // delete the current selection if (selected_brushes.next != &selected_brushes) Brush_Free (selected_brushes.next); XY_ToGridPoint (pressx, pressy, mins); mins[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z/g_qeglobals.d_gridsize)); XY_ToGridPoint (x, y, maxs); maxs[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z/g_qeglobals.d_gridsize)); if (maxs[2] <= mins[2]) maxs[2] = mins[2] + g_qeglobals.d_gridsize; for (i=0 ; i<3 ; i++) { if (mins[i] == maxs[i]) return; // don't create a degenerate brush if (mins[i] > maxs[i]) { temp = mins[i]; mins[i] = maxs[i]; maxs[i] = temp; } } n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); if (!n) return; Brush_AddToList (n, &selected_brushes); Entity_LinkBrush (world_entity, n); Brush_Build( n ); // Sys_UpdateWindows (W_ALL); Sys_UpdateWindows (W_XY| W_CAMERA); }
void Select_Delete (void) { brush_t *brush; selected_face = NULL; g_qeglobals.d_select_mode = sel_brush; g_qeglobals.d_select_count = 0; g_qeglobals.d_num_move_points = 0; while (selected_brushes.next != &selected_brushes) { brush = selected_brushes.next; Brush_Free (brush); } // FIXME: remove any entities with no brushes Sys_UpdateWindows (W_ALL); }
void Map_FreeEntities( CPtrArray *ents ){ int i, j, num_ents, num_brushes; entity_t* e; CPtrArray* brushes; num_ents = ents->GetSize(); for ( i = 0; i < num_ents; i++ ) { e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); for ( j = 0; j < num_brushes; j++ ) Brush_Free( (brush_t*)brushes->GetAt( j ) ); brushes->RemoveAll(); delete (CPtrArray*)e->pData; e->pData = NULL; Entity_Free( e ); } ents->RemoveAll(); }
void Entity_Parse( entity_t *pEntity ){ brush_t *pBrush; // CPtrArray *brushes = NULL; char temptoken[1024]; char *token = Token(); while ( 1 ) { GetToken( true ); // { or } or epair if ( !strcmp( token, "}" ) ) { break; } else if ( !strcmp( token, "{" ) ) { pBrush = Brush_Alloc(); if ( Primitive_Parse( pBrush ) ) { ( (CPtrArray*)pEntity->pData )->Add( pBrush ); } else { Brush_Free( pBrush, true ); } } else { strcpy( temptoken, token ); GetToken( false ); SetKeyValue( pEntity, temptoken, token ); if ( g_MapVersion == MAPVERSION_HL ) { // if we've not god a "wads" key/pair already, then break it into a list. if ( !g_WadList && ( stricmp( temptoken,"wad" ) == 0 ) ) { BuildWadList( token ); } } } } }
/* =============== Entity_Free Frees the entity and any brushes is has. The entity is removed from the global entities list. =============== */ void Entity_Free (entity_t *e) { epair_t *ep, *next; while (e->brushes.onext != &e->brushes) Brush_Free (e->brushes.onext); if (e->next) { e->next->prev = e->prev; e->prev->next = e->next; } for (ep = e->epairs ; ep ; ep=next) { next = ep->next; free (ep->key); free (ep->value); free (ep); } free (e); }
/* Makes the current brushhave the given number of 2d sides */ void Brush_MakeSided(int sides) { int i; vec3_t mins, maxs; brush_t *b; texdef_t *texdef; face_t *f; vec3_t mid; float width,sv,cv; if(sides < 3) { Sys_Status ("Bad sides number", 0); return; } else if(!QE_SingleBrush()) { Sys_Status ("Must have a single brush selected", 0 ); return; } b = selected_brushes.next; Math_VectorCopy(b->mins,mins); Math_VectorCopy(b->maxs,maxs); texdef = &g_qeglobals.d_texturewin.texdef; Brush_Free (b); // find center of brush width = 8; for (i=0 ; i<2 ; i++) { mid[i] = (maxs[i] + mins[i])*0.5; if (maxs[i] - mins[i] > width) width = maxs[i] - mins[i]; } width /= 2; b = qmalloc (sizeof(brush_t)); // create top face f = Face_Alloc(); f->texdef = *texdef; f->next = b->brush_faces; b->brush_faces = f; f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2]; f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2]; f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2]; // create bottom face f = Face_Alloc(); f->texdef = *texdef; f->next = b->brush_faces; b->brush_faces = f; f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; for (i=0 ; i<sides ; i++) { f = Face_Alloc(); f->texdef = *texdef; f->next = b->brush_faces; b->brush_faces = f; sv = sin (i*3.14159265*2/sides); cv = cos (i*3.14159265*2/sides); f->planepts[0][0] = floor(mid[0]+width*cv+0.5); f->planepts[0][1] = floor(mid[1]+width*sv+0.5); f->planepts[0][2] = mins[2]; f->planepts[1][0] = f->planepts[0][0]; f->planepts[1][1] = f->planepts[0][1]; f->planepts[1][2] = maxs[2]; f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5); f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5); f->planepts[2][2] = maxs[2]; } Brush_AddToList (b, &selected_brushes); Entity_LinkBrush (world_entity, b); Brush_Build( b ); Sys_UpdateWindows (W_ALL); }
/* ============= CSG_Merge ============= */ void CSG_Merge(void) { brush_t *b, *next, *newlist, *newbrush; struct entity_s *owner; Sys_Printf ("Merging...\n"); if (selected_brushes.next == &selected_brushes) { Sys_Printf ("No brushes selected.\n"); return; } if (selected_brushes.next->next == &selected_brushes) { Sys_Printf ("At least two brushes have to be selected.\n"); return; } owner = selected_brushes.next->owner; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; if (b->owner->eclass->fixedsize) { // can't use texture from a fixed entity, so don't subtract Sys_Printf ("Cannot add fixed size entities.\n"); return; } if (b->owner != owner) { Sys_Printf ("Cannot add brushes from different entities.\n"); return; } } newlist = NULL; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; Brush_RemoveFromList(b); b->next = newlist; b->prev = NULL; newlist = b; } newbrush = Brush_MergeList(newlist, true); // if the new brush would not be convex if (!newbrush) { // add the brushes back into the selection for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_AddToList(b, &selected_brushes); } Sys_Printf ("Cannot add a set of brushes with a concave hull.\n"); return; } // free the original brushes for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_Free(b); } Brush_AddToList(newbrush, &selected_brushes); Sys_Printf ("Done.\n"); Sys_UpdateWindows (W_ALL); }
/* ============= CSG_Subtract ============= */ void CSG_Subtract (void) { brush_t *b, *s, *fragments, *nextfragment, *frag, *next, *snext; brush_t fragmentlist; int i, numfragments, numbrushes; Sys_Printf ("Subtracting...\n"); if (selected_brushes.next == &selected_brushes) { Sys_Printf ("No brushes selected.\n"); return; } fragmentlist.next = &fragmentlist; fragmentlist.prev = &fragmentlist; numfragments = 0; numbrushes = 0; for (b = selected_brushes.next ; b != &selected_brushes ; b=next) { next = b->next; if (b->owner->eclass->fixedsize) continue; // can't use texture from a fixed entity, so don't subtract // chop all fragments further up for (s = fragmentlist.next; s != &fragmentlist; s = snext) { snext = s->next; for (i=0 ; i<3 ; i++) if (b->mins[i] >= s->maxs[i] - ON_EPSILON || b->maxs[i] <= s->mins[i] + ON_EPSILON) break; if (i != 3) continue; // definately don't touch fragments = Brush_Subtract(s, b); // if the brushes did not really intersect if (fragments == s) continue; // try to merge fragments fragments = Brush_MergeListPairs(fragments, true); // add the fragments to the list for (frag = fragments; frag; frag = nextfragment) { nextfragment = frag->next; frag->next = NULL; frag->owner = s->owner; Brush_AddToList(frag, &fragmentlist); } // free the original brush Brush_Free(s); } // chop any active brushes up for (s = active_brushes.next; s != &active_brushes; s = snext) { snext = s->next; if (s->owner->eclass->fixedsize || s->hiddenBrush) continue; for (i=0 ; i<3 ; i++) if (b->mins[i] >= s->maxs[i] - ON_EPSILON || b->maxs[i] <= s->mins[i] + ON_EPSILON) break; if (i != 3) continue; // definately don't touch fragments = Brush_Subtract(s, b); // if the brushes did not really intersect if (fragments == s) continue; // one extra brush chopped up numbrushes++; // try to merge fragments fragments = Brush_MergeListPairs(fragments, true); // add the fragments to the list for (frag = fragments; frag; frag = nextfragment) { nextfragment = frag->next; frag->next = NULL; frag->owner = s->owner; Brush_AddToList(frag, &fragmentlist); } // free the original brush Brush_Free(s); } } // move all fragments to the active brush list for (frag = fragmentlist.next; frag != &fragmentlist; frag = nextfragment) { nextfragment = frag->next; numfragments++; Brush_RemoveFromList(frag); Brush_AddToList(frag, &active_brushes); } if (numfragments == 0) { Sys_Printf ("Selected brush%s did not intersect with any other brushes.\n", (selected_brushes.next->next == &selected_brushes) ? "":"es"); return; } Sys_Printf ("Done. (created %d fragment%s out of %d brush%s)\n", numfragments, (numfragments == 1)?"":"s", numbrushes, (numbrushes == 1)?"":"es"); Sys_UpdateWindows(W_ALL); }
/* ================ Entity_Parse If onlypairs is set, the classname info will not be looked up, and the entity will not be added to the global list. Used for parsing the project. ================ */ entity_t *Entity_Parse (qboolean onlypairs, brush_t* pList) { entity_t *ent; eclass_t *e; brush_t *b; vec3_t mins, maxs; epair_t *ep; qboolean has_brushes; #ifdef SOF float scale; #endif if (!GetToken (true)) return NULL; if (strcmp (token, "{") ) Error ("ParseEntity: { not found"); ent = (entity_t*)qmalloc (sizeof(*ent)); ent->brushes.onext = ent->brushes.oprev = &ent->brushes; do { if (!GetToken (true)) { Warning ("ParseEntity: EOF without closing brace"); return NULL; } if (!strcmp (token, "}") ) break; if (!strcmp (token, "{") ) { b = Brush_Parse (); if (b != NULL) { b->owner = ent; // add to the end of the entity chain b->onext = &ent->brushes; b->oprev = ent->brushes.oprev; ent->brushes.oprev->onext = b; ent->brushes.oprev = b; } else { break; } } else { ep = ParseEpair (); { // update: the original code here may have been simple, but it meant that every map load/save // the key/value pair fields were reversed in the save file, which messes up SourceSafe when it // tries to delta the two versions during check-in... -slc #if 0 ep->next = ent->epairs; ent->epairs = ep; #else // join this onto the END of the chain instead... // if (ent->epairs == NULL) // special case for if there isn't a chain yet... :-) { ep->next = ent->epairs; ent->epairs = ep; } else { for (epair_t* ep2 = ent->epairs ; ep2 ; ep2=ep2->next) { if (ep2->next == NULL) { // found the end, so... // ep2->next = ep; ep->next = NULL; break; } } } #endif } } } while (1); if (onlypairs) return ent; if (ent->brushes.onext == &ent->brushes) has_brushes = false; else has_brushes = true; GetVectorForKey (ent, "origin", ent->origin); e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes); ent->eclass = e; if (e->fixedsize) { // fixed size entity if (ent->brushes.onext != &ent->brushes) { printf ("Warning: Fixed size entity with brushes\n"); #if 0 while (ent->brushes.onext != &ent->brushes) { // FIXME: this will free the entity and crash! Brush_Free (b); } #endif ent->brushes.next = ent->brushes.prev = &ent->brushes; } // create a custom brush VectorAdd (e->mins, ent->origin, mins); VectorAdd (e->maxs, ent->origin, maxs); float a = 0; if (strnicmp(e->name, "misc_model",10) == 0) { char* p = ValueForKey(ent, "model"); if (p != NULL && strlen(p) > 0) { vec3_t vMin, vMax; a = FloatForKey (ent, "angle"); gEntityToSetBoundsOf = ent; if (GetCachedModel(ent, p, vMin, vMax)) { // create a custom brush VectorAdd (ent->md3Class->mins, ent->origin, mins); VectorAdd (ent->md3Class->maxs, ent->origin, maxs); } } } #ifdef SOF if (strnicmp(e->name, "misc_", 5) == 0 || strnicmp(e->name, "light_", 6) == 0 || strnicmp(e->name, "m_", 2) == 0 || strnicmp(e->name, "item_weapon_", 12)== 0 || strnicmp(e->name, "item_ammo_", 10)== 0 ) a = FloatForKey (ent, "angle"); #endif b = Brush_Create (mins, maxs, &e->texdef); /////// b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; /////// Brush_Build(b); #ifdef SOF scale = FloatForKey (ent, "scale"); if (scale) { Brush_Scale2(e, b, scale, ent->origin,false); } #endif // if (a) // { // vec3_t vAngle; // vAngle[0] = vAngle[1] = 0; // vAngle[2] = a; // Brush_Rotate(b, vAngle, ent->origin, false); // } /* b->owner = ent; b->onext = ent->brushes.onext; b->oprev = &ent->brushes; ent->brushes.onext->oprev = b; ent->brushes.onext = b; */ // do this AFTER doing the brush stuff just above, so don't join to the other "if (a)"... // if (a) { // pick any old value to rotate away to, then back from, to avoid 0/360 weirdness on key-compares // SetKeyValue(ent, "angle", "0", false); // false = no tracking, ie just set the angle and nothing else SetKeyValue(ent, "angle", va("%g",a), true); // true = do tracking, ie actually do the brush rotate } } else { // brush entity if (ent->brushes.next == &ent->brushes) printf ("Warning: Brush entity with no brushes\n"); } // add all the brushes to the main list if (pList) { for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) { b->next = pList->next; pList->next->prev = b; b->prev = pList; pList->next = b; } } return ent; }
/* ============= CSG_Merge ============= */ void CSG_Merge(void) { brush_t *b, *next, *newlist, *newbrush; entity_t *owner; Sys_Status("Merging...\n"); if (selected_brushes.next == &selected_brushes) { Sys_Status("No brushes selected.\n"); return; } if (selected_brushes.next->next == &selected_brushes) { Sys_Status("At least two brushes have to be selected.\n"); return; } owner = selected_brushes.next->owner; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; if (b->owner->eclass->fixedsize || b->modelHandle > 0) { // can't use texture from a fixed entity, so don't subtract Sys_Status("Cannot add fixed size entities.\n"); return; } if (b->pPatch) { Sys_Status("Cannot add patches.\n"); return; } if ( b->brush_faces->d_texture && ( b->brush_faces->d_texture->GetContentFlags() & CONTENTS_NOCSG ) ) { Sys_Status("Cannot add brushes using shaders that don't allows CSG operations.\n"); return; } if (b->owner != owner) { Sys_Status("Cannot add brushes from different entities.\n"); return; } } newlist = NULL; for (b = selected_brushes.next; b != &selected_brushes; b = next) { next = b->next; Brush_RemoveFromList(b); b->next = newlist; b->prev = NULL; newlist = b; } newbrush = Brush_MergeList(newlist, true); // if the new brush would not be convex if (!newbrush) { // add the brushes back into the selection for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_AddToList(b, &selected_brushes); } Sys_Status("Cannot add a set of brushes with a concave hull.\n"); return; } // free the original brushes for (b = newlist; b; b = next) { next = b->next; b->next = NULL; b->prev = NULL; Brush_Free(b); } Brush_AddToList(newbrush, &selected_brushes); Sys_Status ("done.\n"); Sys_UpdateWindows (W_ALL); }