/* Frees the brush with all of its faces and display list. Unlinks the brush from whichever chain it is in. Decrements the owner entity's brushcount. Removes owner entity if this was the last brush unless owner is the world. */ void Brush_Free (brush_t *b) { face_t *f, *next; // free faces for (f=b->brush_faces ; f ; f=next) { next = f->next; Face_Free( f ); } /* for ( i = 0; i < b->d_numwindings; i++ ) { if ( b->d_windings[i] ) { FreeWinding( b->d_windings[i] ); b->d_windings[i] = 0; } } */ // unlink from active/selected list if (b->next) Brush_RemoveFromList (b); // unlink from entity list if (b->onext) Entity_UnlinkBrush (b); free (b); }
/* Turn the currently selected entity back into normal brushes */ void Select_Ungroup (void) { entity_t *e; brush_t *b; e = selected_brushes.next->owner; if (!e || e == world_entity || e->eclass->fixedsize) { Sys_Status ("Not a grouped entity.", 0); return; } for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext) { Brush_RemoveFromList (b); Brush_AddToList (b, &active_brushes); Entity_UnlinkBrush (b); Entity_LinkBrush (world_entity, b); Brush_Build( b ); b->owner = world_entity; } Entity_Free (e); Sys_UpdateWindows (W_ALL); }
/* ============= Select_Ungroup Turn the currently selected entity back into normal brushes ============= */ void Select_Ungroup( void ) { int numselectedgroups; entity_s* e; brush_s* b, *sb; numselectedgroups = 0; for ( sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next ) { e = sb->owner; if ( !e || e == world_entity || e->eclass->fixedsize ) { continue; } for ( b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext ) { //Brush_RemoveFromList (b); //Brush_AddToList (b, &active_brushes); Entity_UnlinkBrush( b ); Entity_LinkBrush( world_entity, b ); Brush_Build( b ); b->owner = world_entity; } Entity_Free( e ); numselectedgroups++; } if ( numselectedgroups <= 0 ) { Sys_Printf( "No grouped entities selected.\n" ); return; } Sys_Printf( "Ungrouped %d entit%s.\n", numselectedgroups, ( numselectedgroups == 1 ) ? "y" : "ies" ); Sys_UpdateWindows( W_ALL ); }
/* ============= Undo_Redo ============= */ void Undo_Redo(void) { undo_t *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pRedoEntity; if (!g_lastredo) { Sys_Status("Nothing left to redo.\n"); return; } if (g_lastundo) { if (!g_lastundo->done) { Sys_Status("WARNING: last undo not finished.\n"); } } // get the last redo redo = g_lastredo; if (g_lastredo->prev) g_lastredo->prev->next = NULL; else g_redolist = NULL; g_lastredo = g_lastredo->prev; // Undo_GeneralStart(redo->operation); // remove current selection Select_Deselect(); // move "created" brushes back to the last undo for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush) { pNextBrush = pBrush->next; if (pBrush->redoId == redo->id) { //move the brush to the undo Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &g_lastundo->brushlist); g_undoMemorySize += Brush_MemorySize(pBrush); pBrush->ownerId = pBrush->owner->entityId; Entity_UnlinkBrush(pBrush); } } // move "created" entities back to the last undo for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) { pNextEntity = pEntity->next; if (pEntity->redoId == redo->id) { // check if this entity is in the redo for (pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next) { // move brushes to the redo entity if (pRedoEntity->entityId == pEntity->entityId) { pRedoEntity->brushes.next = pEntity->brushes.next; pRedoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &g_lastundo->entitylist); g_undoMemorySize += Entity_MemorySize(pEntity); } } // add the undo entities back into the entity list for (pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next) { //if this is the world entity if (pEntity->entityId == world_entity->entityId) { //free the epairs of the world entity Entity_FreeEpairs(world_entity); //set back the original epairs world_entity->epairs = pEntity->epairs; //free the world_entity clone that stored the epairs Entity_Free(pEntity); } else { Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &entities); } } // add the redo brushes back into the selected brushes for (pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next) { Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &active_brushes); for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->entityId == pBrush->ownerId) { Entity_LinkBrush(pEntity, pBrush); break; } } //if the brush is not linked then it should be linked into the world entity if (pEntity == NULL || pEntity == &entities) { Entity_LinkBrush(world_entity, pBrush); } //build the brush //Brush_Build(pBrush); Select_Brush(pBrush); } // Undo_End(); // common->Printf("%s redone.\n", redo->operation); // g_redoId--; // free the undo Mem_Free(redo); // g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); }
/* ============= Undo_Undo ============= */ void Undo_Undo(void) { undo_t *undo, *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pUndoEntity; if (!g_lastundo) { Sys_Status("Nothing left to undo.\n"); return; } if (!g_lastundo->done) { Sys_Status("Undo_Undo: WARNING: last undo not yet finished!\n"); } // get the last undo undo = g_lastundo; if (g_lastundo->prev) g_lastundo->prev->next = NULL; else g_undolist = NULL; g_lastundo = g_lastundo->prev; //allocate a new redo redo = (undo_t *) Mem_ClearedAlloc(sizeof(undo_t), TAG_TOOLS); if (!redo) return; memset(redo, 0, sizeof(undo_t)); redo->brushlist.next = &redo->brushlist; redo->brushlist.prev = &redo->brushlist; redo->entitylist.next = &redo->entitylist; redo->entitylist.prev = &redo->entitylist; if (g_lastredo) g_lastredo->next = redo; else g_redolist = redo; redo->prev = g_lastredo; redo->next = NULL; g_lastredo = redo; redo->time = Sys_DoubleTime(); redo->id = g_redoId++; redo->done = true; redo->operation = undo->operation; //reset the redo IDs of all brushes using the new ID for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } //reset the redo IDs of all entities using thew new ID for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->redoId == redo->id) { pEntity->redoId = 0; } } // remove current selection Select_Deselect(); // move "created" brushes to the redo for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) { pNextBrush = pBrush->next; if (pBrush->undoId == undo->id) { //Brush_Free(pBrush); //move the brush to the redo Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &redo->brushlist); //make sure the ID of the owner is stored pBrush->ownerId = pBrush->owner->entityId; //unlink the brush from the owner entity Entity_UnlinkBrush(pBrush); } } // move "created" entities to the redo for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) { pNextEntity = pEntity->next; if (pEntity->undoId == undo->id) { // check if this entity is in the undo for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) { // move brushes to the undo entity if (pUndoEntity->entityId == pEntity->entityId) { pUndoEntity->brushes.next = pEntity->brushes.next; pUndoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &redo->entitylist); } } // add the undo entities back into the entity list for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) { g_undoMemorySize -= Entity_MemorySize(pEntity); //if this is the world entity if (pEntity->entityId == world_entity->entityId) { //free the epairs of the world entity Entity_FreeEpairs(world_entity); //set back the original epairs world_entity->epairs = pEntity->epairs; //free the world_entity clone that stored the epairs Entity_Free(pEntity); } else { Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &entities); pEntity->redoId = redo->id; } } // add the undo brushes back into the selected brushes for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) { g_undoMemorySize -= Brush_MemorySize(pBrush); Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &active_brushes); for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->entityId == pBrush->ownerId) { Entity_LinkBrush(pEntity, pBrush); break; } } //if the brush is not linked then it should be linked into the world entity if (pEntity == NULL || pEntity == &entities) { Entity_LinkBrush(world_entity, pBrush); } //build the brush //Brush_Build(pBrush); Select_Brush(pBrush); pBrush->redoId = redo->id; } // common->Printf("%s undone.\n", undo->operation); // free the undo g_undoMemorySize -= sizeof(undo_t); Mem_Free(undo); g_undoSize--; g_undoId--; if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; // Sys_BeginWait(); brush_t *b, *next; for (b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) { next = b->next; Brush_Build( b, true, false, false ); } for (b = selected_brushes.next ; b != NULL && b != &selected_brushes ; b=next) { next = b->next; Brush_Build( b, true, false, false ); } Sys_EndWait(); g_bScreenUpdates = true; Sys_UpdateWindows(W_ALL); }
/* ============= Undo_Undo ============= */ void Undo_Undo(boolean bSilent) { // spog - disable undo if undo levels = 0 if (g_PrefsDlg.m_nUndoLevels == 0) { Sys_Printf("Undo_Undo: undo is disabled.\n"); return; } undo_t *undo, *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pUndoEntity; if (!g_lastundo) { Sys_Printf("Nothing left to undo.\n"); return; } if (!g_lastundo->done) { Sys_Printf("Undo_Undo: WARNING: last undo not yet finished!\n"); } // get the last undo undo = g_lastundo; if (g_lastundo->prev) g_lastundo->prev->next = NULL; else g_undolist = NULL; g_lastundo = g_lastundo->prev; //allocate a new redo redo = (undo_t *) malloc(sizeof(undo_t)); if (!redo) return; memset(redo, 0, sizeof(undo_t)); redo->brushlist.next = &redo->brushlist; redo->brushlist.prev = &redo->brushlist; redo->entitylist.next = &redo->entitylist; redo->entitylist.prev = &redo->entitylist; if (g_lastredo) g_lastredo->next = redo; else g_redolist = redo; redo->prev = g_lastredo; redo->next = NULL; g_lastredo = redo; redo->time = Sys_DoubleTime(); redo->id = g_redoId++; redo->done = true; redo->operation = undo->operation; //reset the redo IDs of all brushes using the new ID for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } for (pBrush = selected_brushes.next; pBrush != NULL && pBrush != &selected_brushes; pBrush = pBrush->next) { if (pBrush->redoId == redo->id) { pBrush->redoId = 0; } } //reset the redo IDs of all entities using thew new ID for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) { if (pEntity->redoId == redo->id) { pEntity->redoId = 0; } } // deselect current sutff Select_Deselect(); // move "created" brushes to the redo for (pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush=pNextBrush) { pNextBrush = pBrush->next; if (pBrush->undoId == undo->id) { //Brush_Free(pBrush); //move the brush to the redo Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &redo->brushlist); //make sure the ID of the owner is stored pBrush->ownerId = pBrush->owner->entityId; //unlink the brush from the owner entity Entity_UnlinkBrush(pBrush); } } // move "created" entities to the redo for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity) { pNextEntity = pEntity->next; if (pEntity->undoId == undo->id) { // check if this entity is in the undo for (pUndoEntity = undo->entitylist.next; pUndoEntity != NULL && pUndoEntity != &undo->entitylist; pUndoEntity = pUndoEntity->next) { // move brushes to the undo entity if (pUndoEntity->entityId == pEntity->entityId) { pUndoEntity->brushes.next = pEntity->brushes.next; pUndoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &redo->entitylist); } } // add the undo entities back into the entity list for (pEntity = undo->entitylist.next; pEntity != NULL && pEntity != &undo->entitylist; pEntity = undo->entitylist.next) { g_undoMemorySize -= Entity_MemorySize(pEntity); //if this is the world entity if (pEntity->entityId == world_entity->entityId) { epair_t* tmp = world_entity->epairs; world_entity->epairs = pEntity->epairs; pEntity->epairs = tmp; Entity_Free(pEntity); } else { Entity_RemoveFromList(pEntity); Entity_AddToList(pEntity, &entities); pEntity->redoId = redo->id; } } // add the undo brushes back into the selected brushes for (pBrush = undo->brushlist.next; pBrush != NULL && pBrush != &undo->brushlist; pBrush = undo->brushlist.next) { //Sys_Printf("Owner ID: %i\n",pBrush->ownerId); g_undoMemorySize -= Brush_MemorySize(pBrush); Brush_RemoveFromList(pBrush); Brush_AddToList(pBrush, &active_brushes); for (pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next) // fixes broken undo on entities { //Sys_Printf("Entity ID: %i\n",pEntity->entityId); if (pEntity->entityId == pBrush->ownerId) { Entity_LinkBrush(pEntity, pBrush); break; } } //if the brush is not linked then it should be linked into the world entity //++timo FIXME: maybe not, maybe we've lost this entity's owner! if (pEntity == NULL || pEntity == &entities) { Entity_LinkBrush(world_entity, pBrush); } //build the brush //Brush_Build(pBrush); Select_Brush(pBrush); pBrush->redoId = redo->id; } if (!bSilent) Sys_Printf("%s undone.\n", undo->operation); // free the undo g_undoMemorySize -= sizeof(undo_t); free(undo); g_undoSize--; g_undoId--; if (g_undoId <= 0) g_undoId = 2 * g_undoMaxSize; // g_bScreenUpdates = true; UpdateSurfaceDialog(); Sys_UpdateWindows(W_ALL); }
/*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */ void Map_ImportEntities( CPtrArray *ents, bool bAddSelected = false ){ int num_ents, num_brushes; CPtrArray *brushes; vec3_t mins, maxs; entity_t *e; brush_t *b; face_t *f; int i,j; GPtrArray *new_ents = g_ptr_array_new(); g_qeglobals.bPrimitBrushes = false; brush_t *pBrushList = ( bAddSelected ) ? &selected_brushes : &active_brushes; bool bDoneBPCheck = false; g_qeglobals.bNeedConvert = false; // HACK: find out if this map file was a BP one // check the first brush in the file that is NOT a patch // this will not be necessary when we allow both formats in the same file num_ents = ents->GetSize(); for ( i = 0; !bDoneBPCheck && i < num_ents; i++ ) { e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); for ( j = 0; !bDoneBPCheck && j < num_brushes; j++ ) { /*!todo Allow mixing texdef formats per-face. */ b = (brush_t *)brushes->GetAt( j ); if ( b->patchBrush ) { continue; } bDoneBPCheck = true; int BP_param = -1; if ( b->bBrushDef && !g_qeglobals.m_bBrushPrimitMode ) { BP_param = 0; } else if ( !b->bBrushDef && g_qeglobals.m_bBrushPrimitMode ) { BP_param = 1; } if ( BP_param != -1 ) { switch ( BP_MessageBox( BP_param ) ) { case 0: Map_FreeEntities( ents ); return; case 1: g_qeglobals.bNeedConvert = true; break; case 2: g_qeglobals.bNeedConvert = false; break; } } } } // process the entities into the world geometry num_ents = ents->GetSize(); for ( i = 0; i < num_ents; i++ ) { num_brushes = 0; e = (entity_t*)ents->GetAt( i ); brushes = (CPtrArray*)e->pData; num_brushes = brushes->GetSize(); // link brushes into entity for ( j = 0; j < num_brushes; j++ ) { Entity_LinkBrush( e, (brush_t *)brushes->GetAt( j ) ); g_qeglobals.d_parsed_brushes++; } brushes->RemoveAll(); delete brushes; e->pData = NULL; // set entity origin GetVectorForKey( e, "origin", e->origin ); // set entity eclass /*!\todo Make SetKeyValue check for "classname" change and assign appropriate eclass */ e->eclass = Eclass_ForName( ValueForKey( e, "classname" ), ( e->brushes.onext != &e->brushes ) ); // go through all parsed brushes and build stuff for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { for ( f = b->brush_faces; f != NULL; f = f->next ) { f->pShader = QERApp_Shader_ForName( f->texdef.GetName() ); f->d_texture = f->pShader->getTexture(); } // when brushes are in final state, build the planes and windings // NOTE: also converts BP brushes if g_qeglobals.bNeedConvert is true Brush_Build( b ); } //#define TERRAIN_HACK #undef TERRAIN_HACK #ifdef TERRAIN_HACK if ( ( strcmp( ValueForKey( e, "terrain" ),"1" ) == 0 && strcmp( e->eclass->name,"func_group" ) == 0 ) ) { // two aux pointers to the shaders used in the terrain entity // we don't keep refcount on them since they are only temporary // this avoids doing expensive lookups by name for all faces IShader *pTerrainShader, *pCaulk; pTerrainShader = NULL; pCaulk = QERApp_Shader_ForName( SHADER_CAULK ); for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { if ( pTerrainShader == NULL ) { for ( f = b->brush_faces; f != NULL; f = f->next ) if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { pTerrainShader = f->pShader; } } if ( pTerrainShader ) { for ( f = b->brush_faces; f != NULL; f = f->next ) { if ( strcmp( f->texdef.GetName(), SHADER_CAULK ) != 0 ) { // not caulk Face_SetShader( f, pTerrainShader->getName() ); } else{ Face_SetShader( f, pCaulk->getName() ); } } } else{ Sys_FPrintf( SYS_WRN, "WARNING: no terrain shader found for brush\n" ); } } } #endif #define PATCH_HACK #ifdef PATCH_HACK for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) { // patch hack, to be removed when dependency on brush_faces is removed if ( b->patchBrush ) { Patch_CalcBounds( b->pPatch, mins, maxs ); for ( int i = 0; i < 3; i++ ) { if ( (int)mins[i] == (int)maxs[i] ) { mins[i] -= 4; maxs[i] += 4; } } Brush_Resize( b, mins, maxs ); Brush_Build( b ); } } #endif // add brush for fixedsize entity if ( e->eclass->fixedsize ) { vec3_t mins, maxs; VectorAdd( e->eclass->mins, e->origin, mins ); VectorAdd( e->eclass->maxs, e->origin, maxs ); b = Brush_Create( mins, maxs, &e->eclass->texdef ); Entity_LinkBrush( e, b ); Brush_Build( b ); } for ( b = e->brushes.onext; b != &e->brushes; b = b->onext ) Brush_AddToList( b, pBrushList ); if ( strcmp( e->eclass->name, "worldspawn" ) == 0 ) { if ( world_entity ) { while ( e->brushes.onext != &e->brushes ) { b = e->brushes.onext; Entity_UnlinkBrush( b ); Entity_LinkBrush( world_entity, b ); } Entity_Free( e ); } else { world_entity = e; } } else if ( strcmp( e->eclass->name, "group_info" ) == 0 ) { // it's a group thing! Group_Add( e ); Entity_Free( e ); } else { // fix target/targetname collisions if ( ( g_PrefsDlg.m_bDoTargetFix ) && ( strcmp( ValueForKey( e, "target" ), "" ) != 0 ) ) { GPtrArray *t_ents = g_ptr_array_new(); entity_t *e_target; const char *target = ValueForKey( e, "target" ); qboolean bCollision = FALSE; // check the current map entities for an actual collision for ( e_target = entities.next; e_target != &entities; e_target = e_target->next ) { if ( !strcmp( target, ValueForKey( e_target, "target" ) ) ) { bCollision = TRUE; // make sure the collision is not between two imported entities for ( j = 0; j < (int)new_ents->len; j++ ) { if ( e_target == g_ptr_array_index( new_ents, j ) ) { bCollision = FALSE; } } } } // find the matching targeted entity(s) if ( bCollision ) { for ( j = num_ents - 1; j > 0; j-- ) { e_target = (entity_t*)ents->GetAt( j ); if ( e_target != NULL && e_target != e ) { const char *targetname = ValueForKey( e_target, "targetname" ); if ( ( targetname != NULL ) && ( strcmp( target, targetname ) == 0 ) ) { g_ptr_array_add( t_ents, (gpointer)e_target ); } } } if ( t_ents->len > 0 ) { // link the first to get a unique target/targetname Entity_Connect( e, (entity_t*)g_ptr_array_index( t_ents,0 ) ); // set the targetname of the rest of them manually for ( j = 1; j < (int)t_ents->len; j++ ) SetKeyValue( (entity_t*)g_ptr_array_index( t_ents, j ), "targetname", ValueForKey( e, "target" ) ); } g_ptr_array_free( t_ents, FALSE ); } } // add the entity to the end of the entity list Entity_AddToList( e, &entities ); g_qeglobals.d_num_entities++; // keep a list of ents added to avoid testing collisions against them g_ptr_array_add( new_ents, (gpointer)e ); } } g_ptr_array_free( new_ents, FALSE ); ents->RemoveAll(); g_qeglobals.bNeedConvert = false; }
// // ======================================================================================================================= // Map_ImportFile Timo 09/01/99:: called by CXYWnd::Paste & Map_ImportFile if Map_ImportFile ( prefab ), the buffer // may contain brushes in old format ( conversion needed ) // ======================================================================================================================= // void Map_ImportBuffer(char *buf, bool renameEntities) { entity_t *ent; brush_t *b = NULL; CPtrArray ptrs; Select_Deselect(); Undo_Start("import buffer"); g_qeglobals.d_parsed_brushes = 0; if (buf) { CMapStringToString mapStr; StartTokenParsing(buf); g_qeglobals.d_num_entities = 0; // // Timo will be used in Entity_Parse to detect if a conversion between brush // formats is needed // g_qeglobals.bNeedConvert = false; g_qeglobals.bOldBrushes = false; g_qeglobals.bPrimitBrushes = false; g_qeglobals.mapVersion = 1.0; if (GetToken(true)) { if (stricmp(token, "Version") == 0) { GetToken(false); g_qeglobals.mapVersion = atof(token); common->Printf("Map version: %1.2f\n", g_qeglobals.mapVersion); } else { UngetToken(); } } idDict RemappedNames; // since I can't use "map <string, string>"... sigh. So much for STL... while (1) { // // use the selected brushes list as it's handy ent = Entity_Parse (false, // &selected_brushes); // ent = Entity_Parse(false, &active_brushes); if (!ent) { break; } // end entity for undo Undo_EndEntity(ent); // end brushes for undo for (b = ent->brushes.onext; b && b != &ent->brushes; b = b->onext) { Undo_EndBrush(b); } if (!strcmp(ValueForKey(ent, "classname"), "worldspawn")) { // world brushes need to be added to the current world entity b = ent->brushes.onext; while (b && b != &ent->brushes) { brush_t *bNext = b->onext; Entity_UnlinkBrush(b); Entity_LinkBrush(world_entity, b); ptrs.Add(b); b = bNext; } } else { // the following bit remaps conflicting target/targetname key/value pairs CString str = ValueForKey(ent, "target"); CString strKey; CString strTarget(""); if (str.GetLength() > 0) { if (FindEntity("target", str.GetBuffer(0))) { if (!mapStr.Lookup(str, strKey)) { idStr key; UniqueTargetName(key); strKey = key; mapStr.SetAt(str, strKey); } strTarget = strKey; SetKeyValue(ent, "target", strTarget.GetBuffer(0)); } } /* * str = ValueForKey(ent, "name"); if (str.GetLength() > 0) { if * (FindEntity("name", str.GetBuffer(0))) { if (!mapStr.Lookup(str, strKey)) { * UniqueTargetName(strKey); mapStr.SetAt(str, strKey); } Entity_SetName(ent, * strKey.GetBuffer(0)); } } */ CString cstrNameOld = ValueForKey(ent, "name"); Entity_Name(ent, renameEntities); CString cstrNameNew = ValueForKey(ent, "name"); if (cstrNameOld != cstrNameNew) { RemappedNames.Set(cstrNameOld, cstrNameNew); } // // if (strTarget.GetLength() > 0) SetKeyValue(ent, "target", // strTarget.GetBuffer(0)); // add the entity to the end of the entity list // ent->next = &entities; ent->prev = entities.prev; entities.prev->next = ent; entities.prev = ent; g_qeglobals.d_num_entities++; for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) { ptrs.Add(b); } } } // now iterate through the remapped names, and see if there are any target-connections that need remaking... // // (I could probably write this in half the size with STL, but WTF, work with what we have...) // int iNumKeyVals = RemappedNames.GetNumKeyVals(); for (int iKeyVal=0; iKeyVal < iNumKeyVals; iKeyVal++) { const idKeyValue *pKeyVal = RemappedNames.GetKeyVal( iKeyVal ); LPCSTR psOldName = pKeyVal->GetKey().c_str(); LPCSTR psNewName = pKeyVal->GetValue().c_str(); entity_t *pEntOld = FindEntity("name", psOldName); // original ent we cloned from entity_t *pEntNew = FindEntity("name", psNewName); // cloned ent if (pEntOld && pEntNew) { CString cstrTargetNameOld = ValueForKey(pEntOld, "target"); if (!cstrTargetNameOld.IsEmpty()) { // ok, this ent was targeted at another ent, so it's clone needs updating to point to // the clone of that target, so... // entity_t *pEntOldTarget = FindEntity("name", cstrTargetNameOld); if ( pEntOldTarget ) { LPCSTR psNewTargetName = RemappedNames.GetString( cstrTargetNameOld ); if (psNewTargetName && psNewTargetName[0]) { SetKeyValue(pEntNew, "target", psNewTargetName); } } } } } } // // ::ShowWindow(g_qeglobals.d_hwndEntity, FALSE); // ::LockWindowUpdate(g_qeglobals.d_hwndEntity); // g_bScreenUpdates = false; for (int i = 0; i < ptrs.GetSize(); i++) { Brush_Build(reinterpret_cast < brush_t * > (ptrs[i]), true, false); Select_Brush(reinterpret_cast < brush_t * > (ptrs[i]), true, false); } // ::LockWindowUpdate(NULL); g_bScreenUpdates = true; ptrs.RemoveAll(); // // reset the "need conversion" flag conversion to the good format done in // Map_BuildBrushData // g_qeglobals.bNeedConvert = false; Sys_UpdateWindows(W_ALL); // Sys_MarkMapModified(); mapModified = 1; Undo_End(); }
/* ======================================================================================================================= Entity_Create Creates a new entity out of the selected_brushes list. If the entity class is fixed size, the brushes are only used to find a midpoint. Otherwise, the brushes have their ownership transfered to the new entity. ======================================================================================================================= */ entity_t *Entity_Create(eclass_t *c, bool forceFixed) { entity_t *e; brush_t *b; idVec3 mins, maxs, origin; char text[32]; texdef_t td; brushprimit_texdef_t bp; // check to make sure the brushes are ok for (b = selected_brushes.next; b != &selected_brushes; b = b->next) { if (b->owner != world_entity) { Sys_Status("Entity NOT created, brushes not all from world\n"); Sys_Beep(); return NULL; } } idStr str; if (c->defArgs.GetString("model", "", str) && c->entityModel == NULL) { c->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &c->defArgs ); } // create it e = Entity_New(); e->brushes.onext = e->brushes.oprev = &e->brushes; e->eclass = c; e->epairs.Copy(c->args); SetKeyValue(e, "classname", c->name); Entity_Name(e, false); // add the entity to the entity list Entity_AddToList(e, &entities); if (c->fixedsize) { // // just use the selection for positioning b = selected_brushes.next; for (i=0 ; // i<3 ; i++) { e->origin[i] = b->mins[i] - c->mins[i]; } // Select_GetMid(e->origin); VectorCopy(e->origin, origin); // create a custom brush VectorAdd(c->mins, e->origin, mins); VectorAdd(c->maxs, e->origin, maxs); b = Brush_Create(mins, maxs, &c->texdef); Entity_LinkBrush(e, b); if (c->defMaterial.Length()) { td.SetName(c->defMaterial); Brush_SetTexture(b, &td, &bp, false); } // delete the current selection Select_Delete(); // select the new brush b->next = b->prev = &selected_brushes; selected_brushes.next = selected_brushes.prev = b; Brush_Build(b); } else { Select_GetMid(origin); // change the selected brushes over to the new entity for (b = selected_brushes.next; b != &selected_brushes; b = b->next) { Entity_UnlinkBrush(b); Entity_LinkBrush(e, b); Brush_Build(b); // so the key brush gets a name if (c->defMaterial.Length()) { td.SetName(c->defMaterial); Brush_SetTexture(b, &td, &bp, false); } } //for (int i = 0; i < 3; i++) { // origin[i] = vMin[i] + vMax[i] * 0.5; //} if (!forceFixed) { SetKeyValue(e, "model", ValueForKey(e, "name")); } } sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); SetKeyValue(e, "origin", text); VectorCopy(origin, e->origin); Sys_UpdateWindows(W_ALL); return e; }
/* ============ Entity_Create Creates a new entity out of the selected_brushes list. If the entity class is fixed size, the brushes are only used to find a midpoint. Otherwise, the brushes have their ownershi[ transfered to the new entity. ============ */ entity_t *Entity_Create (eclass_t *c) { entity_t *e; brush_t *b; vec3_t mins, maxs; int i; // check to make sure the brushes are ok for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) if (b->owner != world_entity) { Sys_Printf ("Entity NOT created, brushes not all from world\n"); Sys_Beep (); return NULL; } // create it e = (entity_t*)qmalloc(sizeof(*e)); e->brushes.onext = e->brushes.oprev = &e->brushes; e->eclass = c; SetKeyValue (e, "classname", c->name); // add the entity to the entity list e->next = entities.next; entities.next = e; e->next->prev = e; e->prev = &entities; if (c->fixedsize) { // // just use the selection for positioning // b = selected_brushes.next; for (i=0 ; i<3 ; i++) e->origin[i] = b->mins[i] - c->mins[i]; // create a custom brush VectorAdd (c->mins, e->origin, mins); VectorAdd (c->maxs, e->origin, maxs); b = Brush_Create (mins, maxs, &c->texdef); Entity_LinkBrush (e, b); // delete the current selection Select_Delete (); // select the new brush b->next = b->prev = &selected_brushes; selected_brushes.next = selected_brushes.prev = b; Brush_Build( b ); } else { // // change the selected brushes over to the new entity // for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) { Entity_UnlinkBrush (b); Entity_LinkBrush (e, b); Brush_Build( b ); // so the key brush gets a name } } Sys_UpdateWindows (W_ALL); return e; }
/* ============= Undo_Redo ============= */ void Undo_Redo( void ){ // spog - disable undo if undo levels = 0 if ( g_PrefsDlg.m_nUndoLevels == 0 ) { Sys_Printf( "Undo_Redo: undo is disabled.\n" ); return; } undo_t *redo; brush_t *pBrush, *pNextBrush; entity_t *pEntity, *pNextEntity, *pRedoEntity; if ( !g_lastredo ) { Sys_Printf( "Nothing left to redo.\n" ); return; } if ( g_lastundo ) { if ( !g_lastundo->done ) { Sys_Printf( "WARNING: last undo not finished.\n" ); } } // get the last redo redo = g_lastredo; if ( g_lastredo->prev ) { g_lastredo->prev->next = NULL; } else{g_redolist = NULL; } g_lastredo = g_lastredo->prev; // Undo_GeneralStart( redo->operation ); // remove current selection Select_Deselect(); // move "created" brushes back to the last undo for ( pBrush = active_brushes.next; pBrush != NULL && pBrush != &active_brushes; pBrush = pNextBrush ) { pNextBrush = pBrush->next; if ( pBrush->redoId == redo->id ) { //move the brush to the undo Brush_RemoveFromList( pBrush ); Brush_AddToList( pBrush, &g_lastundo->brushlist ); g_undoMemorySize += Brush_MemorySize( pBrush ); pBrush->ownerId = pBrush->owner->entityId; Entity_UnlinkBrush( pBrush ); } } // move "created" entities back to the last undo for ( pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pNextEntity ) { pNextEntity = pEntity->next; if ( pEntity->redoId == redo->id ) { // check if this entity is in the redo for ( pRedoEntity = redo->entitylist.next; pRedoEntity != NULL && pRedoEntity != &redo->entitylist; pRedoEntity = pRedoEntity->next ) { // move brushes to the redo entity if ( pRedoEntity->entityId == pEntity->entityId ) { pRedoEntity->brushes.next = pEntity->brushes.next; pRedoEntity->brushes.prev = pEntity->brushes.prev; pEntity->brushes.next = &pEntity->brushes; pEntity->brushes.prev = &pEntity->brushes; } } // //Entity_Free(pEntity); //move the entity to the redo Entity_RemoveFromList( pEntity ); Entity_AddToList( pEntity, &g_lastundo->entitylist ); g_undoMemorySize += Entity_MemorySize( pEntity ); } } // add the undo entities back into the entity list for ( pEntity = redo->entitylist.next; pEntity != NULL && pEntity != &redo->entitylist; pEntity = redo->entitylist.next ) { //if this is the world entity if ( pEntity->entityId == world_entity->entityId ) { epair_t* tmp = world_entity->epairs; world_entity->epairs = pEntity->epairs; pEntity->epairs = tmp; Entity_Free( pEntity ); } else { Entity_RemoveFromList( pEntity ); Entity_AddToList( pEntity, &entities ); } } // add the redo brushes back into the selected brushes for ( pBrush = redo->brushlist.next; pBrush != NULL && pBrush != &redo->brushlist; pBrush = redo->brushlist.next ) { Brush_RemoveFromList( pBrush ); Brush_AddToList( pBrush, &active_brushes ); for ( pEntity = entities.next; pEntity != NULL && pEntity != &entities; pEntity = pEntity->next ) // fixes broken undo on entities { if ( pEntity->entityId == pBrush->ownerId ) { Entity_LinkBrush( pEntity, pBrush ); break; } } //if the brush is not linked then it should be linked into the world entity if ( pEntity == NULL || pEntity == &entities ) { Entity_LinkBrush( world_entity, pBrush ); } //build the brush //Brush_Build(pBrush); Select_Brush( pBrush ); } // Undo_End(); // Sys_Printf( "%s redone.\n", redo->operation ); // g_redoId--; // free the undo free( redo ); // g_bScreenUpdates = true; UpdateSurfaceDialog(); Sys_UpdateWindows( W_ALL ); }
// //================ //Map_ImportFile // Timo 09/01/99 : called by CXYWnd::Paste & Map_ImportFile // if Map_ImportFile ( prefab ), the buffer may contain brushes in old format ( conversion needed ) //================ // void Map_ImportBuffer (char* buf) { entity_t* ent; brush_t* b = NULL; CPtrArray ptrs; Select_Deselect(); Undo_Start("import buffer"); g_qeglobals.d_parsed_brushes = 0; if (buf) { CMapStringToString mapStr; StartTokenParsing (buf); g_qeglobals.d_num_entities = 0; // Timo // will be used in Entity_Parse to detect if a conversion between brush formats is needed g_qeglobals.bNeedConvert = false; g_qeglobals.bOldBrushes = false; g_qeglobals.bPrimitBrushes = false; while (1) { // use the selected brushes list as it's handy //ent = Entity_Parse (false, &selected_brushes); ent = Entity_Parse (false, &active_brushes); if (!ent) break; //end entity for undo Undo_EndEntity(ent); //end brushes for undo for(b = ent->brushes.onext; b && b != &ent->brushes; b = b->onext) { Undo_EndBrush(b); } if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) { // world brushes need to be added to the current world entity b=ent->brushes.onext; while (b && b != &ent->brushes) { brush_t* bNext = b->onext; Entity_UnlinkBrush(b); Entity_LinkBrush(world_entity, b); ptrs.Add(b); b = bNext; } } else { // the following bit remaps conflicting target/targetname key/value pairs CString str = ValueForKey(ent, "target"); CString strKey; CString strTarget(""); if (str.GetLength() > 0) { if (FindEntity("target", str.GetBuffer(0))) { if (!mapStr.Lookup(str, strKey)) { UniqueTargetName(strKey); mapStr.SetAt(str, strKey); } strTarget = strKey; SetKeyValue(ent, "target", strTarget.GetBuffer(0)); } } str = ValueForKey(ent, "targetname"); if (str.GetLength() > 0) { if (FindEntity("targetname", str.GetBuffer(0))) { if (!mapStr.Lookup(str, strKey)) { UniqueTargetName(strKey); mapStr.SetAt(str, strKey); } SetKeyValue(ent, "targetname", strKey.GetBuffer(0)); } } //if (strTarget.GetLength() > 0) // SetKeyValue(ent, "target", strTarget.GetBuffer(0)); // add the entity to the end of the entity list ent->next = &entities; ent->prev = entities.prev; entities.prev->next = ent; entities.prev = ent; g_qeglobals.d_num_entities++; for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) { ptrs.Add(b); } } } } //::ShowWindow(g_qeglobals.d_hwndEntity, FALSE); //::LockWindowUpdate(g_qeglobals.d_hwndEntity); g_bScreenUpdates = false; for (int i = 0; i < ptrs.GetSize(); i++) { Brush_Build(reinterpret_cast<brush_t*>(ptrs[i]), true, false); Select_Brush(reinterpret_cast<brush_t*>(ptrs[i]), true, false); } //::LockWindowUpdate(NULL); g_bScreenUpdates = true; ptrs.RemoveAll(); // reset the "need conversion" flag // conversion to the good format done in Map_BuildBrushData g_qeglobals.bNeedConvert=false; Sys_UpdateWindows (W_ALL); //Sys_MarkMapModified(); modified = true; Undo_End(); }