示例#1
0
/*
=============
Undo_AddEntity
=============
*/
void Undo_AddEntity(entity_t *entity)
{
	// spog - disable undo if undo levels = 0
	if (g_PrefsDlg.m_nUndoLevels == 0)
	{
#ifdef DBG_UNDO
		Sys_Printf("Undo_AddEntity: undo is disabled.\n");
#endif
		return;
	}


	entity_t* pClone;

	if (!g_lastundo)
	{
		Sys_Printf("Undo_AddEntity: no last undo.\n");
		return;
	}
	//if the entity is already in the undo
	if (Undo_EntityInUndo(g_lastundo, entity))
		return;
	//clone the entity
	pClone = Entity_Clone(entity);
	//save the old undo ID for previous undos
	pClone->undoId = entity->undoId;
	//save the entity ID (we need a full clone)
	pClone->entityId = entity->entityId;
	//
	Entity_AddToList(pClone, &g_lastundo->entitylist);
	//
	g_undoMemorySize += Entity_MemorySize(pClone);
}
示例#2
0
/*
=============
Undo_AddEntity
=============
*/
void Undo_AddEntity(entity_t *entity)
{
	entity_t* pClone;

	if (!g_lastundo)
	{
		Sys_Status("Undo_AddEntity: no last undo.\n");
		return;
	}
	//if the entity is already in the undo
	if (Undo_EntityInUndo(g_lastundo, entity))
		return;
	//clone the entity
	pClone = Entity_Clone(entity);
	//NOTE: Entity_Clone adds the entity to the entity list
	//		so we remove it from that list here
	Entity_RemoveFromList(pClone);
	//save the old undo ID for previous undos
	pClone->undoId = entity->undoId;
	//save the entity ID (we need a full clone)
	pClone->entityId = entity->entityId;
	//
	Entity_AddToList(pClone, &g_lastundo->entitylist);
	//
	g_undoMemorySize += Entity_MemorySize(pClone);
}
示例#3
0
/*
 =======================================================================================================================
    Entity_Clone
 =======================================================================================================================
 */
entity_t *Entity_Clone(entity_t *e) {
	entity_t	*n;

	n = Entity_New();
	n->brushes.onext = n->brushes.oprev = &n->brushes;
	n->eclass = e->eclass;
	n->rotation = e->rotation;
	n->origin = e->origin;

	// add the entity to the entity list
	Entity_AddToList(n, &entities);

	n->epairs  = e->epairs;

	return n;
}
示例#4
0
/*
=============
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);
}
示例#5
0
/*
=============
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);
}
示例#6
0
/*
=============
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);
}
示例#7
0
/*!\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;
}
/*
 =======================================================================================================================
    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;
}
示例#9
0
/*
   =============
   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 );
}