示例#1
0
/*
==============
CSG_SplitBrushByFace

The incoming brush is NOT freed.
The incoming face is NOT left referenced.
==============
*/
void CSG_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back)
{
	brush_t	*b;
	face_t	*nf;
	vec3_t	temp;

	b = Brush_Clone (in);
	nf = Face_Clone (f);

	nf->texdef = b->brush_faces->texdef;
	nf->next = b->brush_faces;
	b->brush_faces = nf;

	Brush_Build( b );
	Brush_RemoveEmptyFaces ( b );
	if ( !b->brush_faces )
	{	// completely clipped away
		Brush_Free (b);
		*back = NULL;
	}
	else
	{
		Entity_LinkBrush (in->owner, b);
		*back = b;
	}

	b = Brush_Clone (in);
	nf = Face_Clone (f);
	// swap the plane winding
	VectorCopy (nf->planepts[0], temp);
	VectorCopy (nf->planepts[1], nf->planepts[0]);
	VectorCopy (temp, nf->planepts[1]);

	nf->texdef = b->brush_faces->texdef;
	nf->next = b->brush_faces;
	b->brush_faces = nf;

	Brush_Build( b );
	Brush_RemoveEmptyFaces ( b );
	if ( !b->brush_faces )
	{	// completely clipped away
		Brush_Free (b);
		*front = NULL;
	}
	else
	{
		Entity_LinkBrush (in->owner, b);
		*front = b;
	}
}
示例#2
0
/*	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);
}
/*
 =======================================================================================================================
    AddRegionBrushes a regioned map will have temp walls put up at the region boundary
 =======================================================================================================================
 */
void AddRegionBrushes(void)
{
	idVec3		mins, maxs;
	int			i;
	texdef_t	td;

	if (!region_active) {
		return;
	}

	memset(&td, 0, sizeof(td));
	td = g_qeglobals.d_texturewin.texdef;

	// strcpy (td.name, "REGION");
	td.SetName("textures/REGION");

	const int REGION_WIDTH = 1024;


	mins[0] = region_mins[0] - REGION_WIDTH;
	maxs[0] = region_mins[0] + 1;
	mins[1] = region_mins[1] - REGION_WIDTH;
	maxs[1] = region_maxs[1] + REGION_WIDTH;
	mins[2] = MIN_WORLD_COORD;
	maxs[2] = MAX_WORLD_COORD;
	region_sides[0] = Brush_Create(mins, maxs, &td);


	mins[0] = region_maxs[0] - 1;
	maxs[0] = region_maxs[0] + REGION_WIDTH;
	region_sides[1] = Brush_Create(mins, maxs, &td);

	mins[0] = region_mins[0] - REGION_WIDTH;
	maxs[0] = region_maxs[0] + REGION_WIDTH;
	mins[1] = region_mins[1] - REGION_WIDTH;
	maxs[1] = region_mins[1] + 1;
	region_sides[2] = Brush_Create(mins, maxs, &td);

	mins[1] = region_maxs[1] - 1;
	maxs[1] = region_maxs[1] + REGION_WIDTH;
	region_sides[3] = Brush_Create(mins, maxs, &td);

	mins = region_mins;
	maxs = region_maxs;
	maxs[2] = mins[2] + REGION_WIDTH;
	region_sides[4] = Brush_Create(mins, maxs, &td);

	mins = region_mins;
	maxs = region_maxs;
	mins[2] = maxs[2] - REGION_WIDTH;
	region_sides[5] = Brush_Create(mins, maxs, &td);

	for (i = 0; i < 6; i++) {
		Brush_AddToList(region_sides[i], &selected_brushes);
		Entity_LinkBrush(world_entity, region_sides[i]);
		Brush_Build(region_sides[i]);
	}
}
// creates a dummy brush in the active brushes list
// FIXME : is this one really USED ?
void WINAPI QERApp_CreateBrush(vec3_t vMin, vec3_t vMax)
{
	AFX_MANAGE_STATE(AfxGetStaticModuleState());
	
	brush_t* pBrush = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
	Entity_LinkBrush (world_entity, pBrush);
	Brush_Build(pBrush);
	Brush_AddToList (pBrush, &active_brushes);
	Select_Brush(pBrush);
	Sys_UpdateWindows(W_ALL);
}
// the vpBrush needs to be in m_BrushHandles
//++timo add a debug check to see if we found the brush handle
// NOTE : seems there's no way to check vpEntity is valid .. this is dangerous
// links the brush to its entity, everything else is done when commiting the entity to the map
void CPlugInManager::CommitBrushHandleToEntity(LPVOID vpBrush, LPVOID vpEntity)
{
	brush_t* pb;
	entity_t* pe;
	for (int i=0 ; i < m_BrushHandles.GetSize() ; i++)
	{
		if (vpBrush == m_BrushHandles.GetAt(i))
		{
			m_BrushHandles.RemoveAt(i);
			pb = reinterpret_cast<brush_t*>(vpBrush);
			pe = reinterpret_cast<entity_t *>(vpEntity);
			Entity_LinkBrush (pe, pb);
		}
	}
	Sys_UpdateWindows(W_ALL);
}
void CPlugInManager::CommitBrushHandleToMap(void * vp)
{
  g_bScreenUpdates = false; 
  for (int i = 0; i < m_BrushHandles.GetSize(); i++)
  {
    brush_t *pb = reinterpret_cast<brush_t*>(m_BrushHandles.GetAt(i));
    if (pb == reinterpret_cast<brush_t*>(vp))
    {
      m_BrushHandles.RemoveAt(i);
	  Entity_LinkBrush (world_entity, pb);
      Brush_Build(pb);
	  Brush_AddToList (pb, &active_brushes);
      Select_Brush(pb);
    }
  }
  g_bScreenUpdates = true; 
  Sys_UpdateWindows(W_ALL);
}
示例#7
0
/*
==============
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);
}
示例#8
0
brush_t *AddBrushForTerrain( terrainMesh_t *pm, bool bLinkToWorld ) {
	int		j;
	vec3_t	vMin;
	vec3_t	vMax;
	brush_t	*b;
	face_t	*f;

	// calculate the face normals
	Terrain_CalcNormals( pm );
   
	// find the farthest points in x,y,z
	Terrain_CalcBounds( pm, vMin, vMax );

	for( j = 0; j < 3; j++ ) {
		if ( vMin[ j ] == vMax[ j ] ) {
			vMin[ j ] -= 4;
			vMax[ j ] += 4;
		}
	}

	b = Brush_Create( vMin, vMax, &pm->heightmap->tri.texdef );

	for( f = b->brush_faces; f != NULL; f = f->next ) {
		// copy the texdef to the brush faces texdef
		f->texdef = pm->heightmap->tri.texdef;
	}

	// FIXME: this entire type of linkage needs to be fixed
	b->pTerrain		= pm;
	b->terrainBrush = true;
	pm->pSymbiot    = b;
	pm->bSelected   = false;
	pm->bDirty      = true;
	pm->nListID		= -1;

	if ( bLinkToWorld ) {
		Brush_AddToList( b, &active_brushes );
		Entity_LinkBrush( world_entity, b );
		Brush_Build( b, true );
	}
  
	return b;
}
示例#9
0
/*
===========
AddRegionBrushes

a regioned map will have temp walls put up at the region boundary
===========
*/
void AddRegionBrushes (void)
{
	vec3_t	mins, maxs;
	int		i;
	texdef_t	td;

	if (!region_active)
		return;

	memset (&td, 0, sizeof(td));
	//strcpy (td.name, "REGION");
	td.SetName("REGION");

	mins[0] = region_mins[0] - 16;
	maxs[0] = region_mins[0] + 1;
	mins[1] = region_mins[1] - 16;
	maxs[1] = region_maxs[1] + 16;
	mins[2] = MIN_WORLD_COORD;
	maxs[2] = MAX_WORLD_COORD;
	region_sides[0] = Brush_Create (mins, maxs, &td);

	mins[0] = region_maxs[0] - 1;
	maxs[0] = region_maxs[0] + 16;
	region_sides[1] = Brush_Create (mins, maxs, &td);

	mins[0] = region_mins[0] - 16;
	maxs[0] = region_maxs[0] + 16;
	mins[1] = region_mins[1] - 16;
	maxs[1] = region_mins[1] + 1;
	region_sides[2] = Brush_Create (mins, maxs, &td);

	mins[1] = region_maxs[1] - 1;
	maxs[1] = region_maxs[1] + 16;
	region_sides[3] = Brush_Create (mins, maxs, &td);

	for (i=0 ; i<4 ; i++)
	{
		Brush_AddToList (region_sides[i], &selected_brushes);
		Entity_LinkBrush (world_entity, region_sides[i]);
		Brush_Build( region_sides[i] );
	}
}
示例#10
0
void Curve_BevelBrush( brush_t *b ) {
	curveBlock_t	*cb;
	face_t			*f;

	// make a copy without any curve flags, but keeping the negative flag
	bevelBrush = Brush_Clone( b );
	for (f = bevelBrush->brush_faces ; f ; f = f->next) {
		f->texdef.flags &= ~SURF_CURVE;
	}
	bevelBrush->curveBrush = false;

	cb = BrushToCurveBlock(b);
	SubdivideCurveBlock (cb);

	Brush_Build( bevelBrush );
	Brush_AddToList( bevelBrush, &active_brushes );
	Entity_LinkBrush( b->owner, bevelBrush );

	Sys_UpdateWindows (W_ALL);

	bevelBrush = NULL;
}
示例#11
0
/*
=============
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 );
}
示例#12
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);
}
示例#13
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);
}
示例#14
0
/*
=============
Brush_MergeList

 Tries to merge all brushes in the list into one new brush.
 The input brush list stays intact.
 Returns NULL if no merged brush can be created.
 To create a new brush the brushes in the list may not overlap and
 the outer faces of the brushes together should make a new convex brush.

 if onlyshape is true then the merge is allowed based on the shape only
 otherwise the texture references of faces in the same plane have to
 be the same as well.
=============
*/
brush_t *Brush_MergeList(brush_t *brushlist, int onlyshape)
{
	brush_t *brush1, *brush2, *brush3, *newbrush;
	face_t *face1, *face2, *face3, *newface, *f;

	if (!brushlist) return NULL;
	for (brush1 = brushlist; brush1; brush1 = brush1->next)
	{
		// check if the new brush would be convex... flipped planes make a brush concave
		for (face1 = brush1->brush_faces; face1; face1 = face1->next)
		{
			// don't check face1 if it touches another brush
			for (brush2 = brushlist; brush2; brush2 = brush2->next)
			{
				if (brush2 == brush1) continue;
				for (face2 = brush2->brush_faces; face2; face2 = face2->next)
				{
					if (Plane_Equal(&face1->plane, &face2->plane, true))
					{
						break;
					}
				}
				if (face2) break;
			}
			// if face1 touches another brush
			if (brush2) continue;
			//
			for (brush2 = brush1->next; brush2; brush2 = brush2->next)
			{
				// don't check the faces of brush 2 touching another brush
				for (face2 = brush2->brush_faces; face2; face2 = face2->next)
				{
					for (brush3 = brushlist; brush3; brush3 = brush3->next)
					{
						if (brush3 == brush2) continue;
						for (face3 = brush3->brush_faces; face3; face3 = face3->next)
						{
							if (Plane_Equal(&face2->plane, &face3->plane, true)) break;
						}
						if (face3) break;
					}
					// if face2 touches another brush
					if (brush3) continue;
					//
					if (Plane_Equal(&face1->plane, &face2->plane, false))
					{
						//if the texture references should be the same but are not
						if (!onlyshape && stricmp(face1->texdef.name, face2->texdef.name) != 0) return NULL;
						continue;
					}
					//
					if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
											face1->plane.normal, face2->plane.normal,
											face1->plane.dist, face2->plane.dist))
					{
						return NULL;
					}
				}
			}
		}
	}
	//
	newbrush = Brush_Alloc();
	//
	for (brush1 = brushlist; brush1; brush1 = brush1->next)
	{
		for (face1 = brush1->brush_faces; face1; face1 = face1->next)
		{
			// don't add face1 to the new brush if it touches another brush
			for (brush2 = brushlist; brush2; brush2 = brush2->next)
			{
				if (brush2 == brush1) continue;
				for (face2 = brush2->brush_faces; face2; face2 = face2->next)
				{
					if (Plane_Equal(&face1->plane, &face2->plane, true))
					{
						break;
					}
				}
				if (face2) break;
			}
			if (brush2) continue;
			// don't add faces with the same plane twice
			for (f = newbrush->brush_faces; f; f = f->next)
			{
				if (Plane_Equal(&face1->plane, &f->plane, false))
					break;
				if (Plane_Equal(&face1->plane, &f->plane, true))
					break;
			}
			if (f)
				continue;
			//
			newface = Face_Alloc();
			newface->texdef = face1->texdef;
			VectorCopy(face1->planepts[0], newface->planepts[0]);
			VectorCopy(face1->planepts[1], newface->planepts[1]);
			VectorCopy(face1->planepts[2], newface->planepts[2]);
			newface->plane = face1->plane;
			newface->next = newbrush->brush_faces;
			newbrush->brush_faces = newface;
		}
	}
	// link the new brush to an entity
	Entity_LinkBrush (brushlist->owner, newbrush);
	// build windings for the faces
	Brush_BuildWindings( newbrush);
	return newbrush;
}
示例#15
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 );
}
示例#16
0
/*
=============
Brush_Merge

 Returns a new brush that is created by merging brush1 and brush2.
 May return NULL if brush1 and brush2 do not create a convex brush when merged.
 The input brushes brush1 and brush2 stay intact.

 if onlyshape is true then the merge is allowed based on the shape only
 otherwise the texture references of faces in the same plane have to
 be the same as well.
=============
*/
brush_t *Brush_Merge(brush_t *brush1, brush_t *brush2, int onlyshape)
{
	int i, shared;
	brush_t *newbrush;
	face_t *face1, *face2, *newface, *f;

	// check for bounding box overlapp
	for (i = 0; i < 3; i++)
	{
		if (brush1->mins[i] > brush2->maxs[i] + ON_EPSILON
				|| brush1->maxs[i] < brush2->mins[i] - ON_EPSILON)
		{
			// never merge if the brushes overlap
			return NULL;
		}
	}
	//
	shared = 0;
	// check if the new brush would be convex... flipped planes make a brush non-convex
	for (face1 = brush1->brush_faces; face1; face1 = face1->next)
	{
		// don't check the faces of brush 1 and 2 touching each other
		for (face2 = brush2->brush_faces; face2; face2 = face2->next)
		{
			if (Plane_Equal(&face1->plane, &face2->plane, true))
			{
				shared++;
				// there may only be ONE shared side
				if (shared > 1)
					return NULL;
				break;
			}
		}
		// if this face plane is shared
		if (face2) continue;
		//
		for (face2 = brush2->brush_faces; face2; face2 = face2->next)
		{
			// don't check the faces of brush 1 and 2 touching each other
			for (f = brush1->brush_faces; f; f = f->next)
			{
				if (Plane_Equal(&face2->plane, &f->plane, true)) break;
			}
			if (f)
				continue;
			//
			if (Plane_Equal(&face1->plane, &face2->plane, false))
			{
				//if the texture references should be the same but are not
				if (!onlyshape && stricmp(face1->texdef.name, face2->texdef.name) != 0) return NULL;
				continue;
			}
			//
			if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
									face1->plane.normal, face2->plane.normal,
									face1->plane.dist, face2->plane.dist))
			{
				return NULL;
			} //end if
		} //end for
	} //end for
	//
	newbrush = Brush_Alloc();
	//
	for (face1 = brush1->brush_faces; face1; face1 = face1->next)
	{
		// don't add the faces of brush 1 and 2 touching each other
		for (face2 = brush2->brush_faces; face2; face2 = face2->next)
		{
			if (Plane_Equal(&face1->plane, &face2->plane, true))
				break;
		}
		if (face2)
			continue;
		// don't add faces with the same plane twice
		for (f = newbrush->brush_faces; f; f = f->next)
		{
			if (Plane_Equal(&face1->plane, &f->plane, false))
				break;
			if (Plane_Equal(&face1->plane, &f->plane, true))
				break;
		}
		if (f)
			continue;
		//
		newface = Face_Alloc();
		newface->texdef = face1->texdef;
		VectorCopy(face1->planepts[0], newface->planepts[0]);
		VectorCopy(face1->planepts[1], newface->planepts[1]);
		VectorCopy(face1->planepts[2], newface->planepts[2]);
		newface->plane = face1->plane;
		newface->next = newbrush->brush_faces;
		newbrush->brush_faces = newface;
	}
	//
	for (face2 = brush2->brush_faces; face2; face2 = face2->next)
	{
		// don't add the faces of brush 1 and 2 touching each other
		for (face1 = brush1->brush_faces; face1; face1 = face1->next)
		{
			if (Plane_Equal(&face2->plane, &face1->plane, true))
				break;
		}
		if (face1)
			continue;
		// don't add faces with the same plane twice
		for (f = newbrush->brush_faces; f; f = f->next)
		{
			if (Plane_Equal(&face2->plane, &f->plane, false))
				break;
			if (Plane_Equal(&face2->plane, &f->plane, true))
				break;
		}
		if (f)
			continue;
		//
		newface = Face_Alloc();
		newface->texdef = face2->texdef;
		VectorCopy(face2->planepts[0], newface->planepts[0]);
		VectorCopy(face2->planepts[1], newface->planepts[1]);
		VectorCopy(face2->planepts[2], newface->planepts[2]);
		newface->plane = face2->plane;
		newface->next = newbrush->brush_faces;
		newbrush->brush_faces = newface;
	}
	// link the new brush to an entity
	Entity_LinkBrush (brush1->owner, newbrush);
	// build windings for the faces
	Brush_BuildWindings(newbrush);
	return newbrush;
}
示例#17
0
/*
============
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;
}
示例#18
0
void DoTower(void)
{
	brush_t*	brush1 = NULL;
	brush_t*	brush2 = NULL;
	brush_t*	newBrush = NULL;
	brush_t*	tempBrush = NULL;
	face_t*		topFace = NULL;
	face_t*		bottomFace = NULL;
	face_t*		curFace;
	face_t*		faceList;
	int			zFlag = 0;
	int			i = 0; // loop counter

	if (g_qeglobals.d_select_count != 2)
	{
		Sys_Printf ("Error: you must have exactly 2 brushes selected\n");
		Sys_Beep ();
		return;
	}
	brush1 = selected_brushes.next;
	brush2 = selected_brushes.next->next;
//	establish brush1 as the upper brush
	if (brush2->maxs[2] > brush1->mins[2])
	{
		tempBrush = brush1;
		brush1 = brush2;
		brush2 = tempBrush;
	}
//	test to insure brushes do not "overlap" in the Z direction
	if (brush2->maxs[2] > brush1->mins[2])
	{
		Sys_Printf ("Brushes are not separated in the Z direction!");
		Sys_Beep();
		return;
	}
//  find the bottom Z plane (topFace) in 1 and top Z plane in 2 (bottomFace)
	topFace = brush1->brush_faces;
	while (topFace != NULL)
	{
		zFlag = 0;
		for (i = 0; i<3; i++)
		{
			if (abs(topFace->planepts[i][2] - brush1->mins[2]) < TOWER_EPSILON)
			{
				zFlag++;
			}
		}
		if (zFlag == 3)
		{
			break;
		}
		else
		{
			topFace = topFace->next;
		}
	}
	if (topFace == NULL)
	{
		Sys_Printf("Couldn't find flat bottom-face in top brush", 0);
		Sys_Beep();
		return;
	}
	bottomFace = brush2->brush_faces;
	while (bottomFace != NULL)
	{
		zFlag = 0;
		for (i = 0; i<3; i++)
		{
			if (abs(bottomFace->planepts[i][2] - brush2->maxs[2]) < TOWER_EPSILON)
			{
				zFlag++;
			}
		}
		if (zFlag == 3)
		{
			break;
		}
		else
		{
			bottomFace = bottomFace->next;
		}
	}
	if (bottomFace == NULL)
	{
		Sys_Printf ("Couldn't find flat top-face in bottom brush", 0);
		Sys_Beep();
		return;
	}
//	count vertices on top and bottom planes to make sure they are equal
	if (topFace->face_winding->numpoints != bottomFace->face_winding->numpoints)
	{

		Sys_Printf ("Top and Bottom faces don't have same #'s of vertices!", 0);
		Sys_Beep();
		return;
	}
//  put top and bottom faces on brush
//  reverse winding for top and bottom
	faceList = Face_Alloc();
	for ( i = 0; i<3; i++)
	{
		VectorCopy(topFace->planepts[2-i],faceList->planepts[i]);
	}
	curFace = Face_Alloc();
	for ( i = 0; i < 3; i++)
	{
		VectorCopy(bottomFace->planepts[2-i],curFace->planepts[i]);
	}
	curFace->next = faceList;
	faceList = curFace;
	
	curFace = MakePlaneList(topFace, bottomFace);
	if (curFace == NULL)
	{
		Sys_Printf ("Couldn't make planes for tower!", 0);
		Sys_Beep();
		return;
	}
	else
	{
		faceList->next->next = curFace;
	}

	newBrush = (brush_t*)qmalloc(sizeof(brush_t));
	newBrush->brush_faces = faceList;
	Select_Deselect();
	Brush_AddToList (newBrush, &selected_brushes);

	Entity_LinkBrush (world_entity, newBrush);

	Brush_Build(newBrush);
//	UNDO_FinishBrushAdd("&Undo Tower");
	Sys_UpdateWindows(W_ALL);
	return;

}
示例#19
0
/*
============
Select_Clone

Creates an exact duplicate of the selection in place, then moves
the selected brushes off of their old positions
============
*/
void Select_Clone( void )
{
#if 1
	ASSERT( g_pParentWnd->ActiveXY() );
	g_bScreenUpdates = false;
	g_pParentWnd->ActiveXY()->Copy();
	g_pParentWnd->ActiveXY()->Paste();
	g_pParentWnd->NudgeSelection( 2, g_qeglobals.d_gridsize );
	g_pParentWnd->NudgeSelection( 3, g_qeglobals.d_gridsize );
	g_bScreenUpdates = true;
	Sys_UpdateWindows( W_ALL );
#else
	
	brush_s*        b, *b2, *n, *next, *next2;
	vec3_t      delta;
	entity_s*   e;
	
	g_qeglobals.d_workcount++;
	clearSelection();
	
	delta[0] = g_qeglobals.d_gridsize;
	delta[1] = g_qeglobals.d_gridsize;
	delta[2] = 0;
	
	for ( b = selected_brushes.next ; b != &selected_brushes ; b = next )
	{
		next = b->next;
		// if the brush is a world brush, handle simply
		if ( b->owner == world_entity )
		{
			n = Brush_Clone( b );
			Brush_AddToList( n, &active_brushes );
			Entity_LinkBrush( world_entity, n );
			Brush_Build( n );
			Brush_Move( b, delta );
			continue;
		}
	
		e = Entity_Clone( b->owner );
		// clear the target / targetname
		DeleteKey( e, "target" );
		DeleteKey( e, "targetname" );
	
		// if the brush is a fixed size entity, create a new entity
		if ( b->owner->eclass->fixedsize )
		{
			n = Brush_Clone( b );
			Brush_AddToList( n, &active_brushes );
			Entity_LinkBrush( e, n );
			Brush_Build( n );
			Brush_Move( b, delta );
			continue;
		}
	
		// brush is a complex entity, grab all the other ones now
	
		next = &selected_brushes;
	
		for ( b2 = b ; b2 != &selected_brushes ; b2 = next2 )
		{
			next2 = b2->next;
			if ( b2->owner != b->owner )
			{
				if ( next == &selected_brushes )
					next = b2;
				continue;
			}
	
			// move b2 to the start of selected_brushes,
			// so it won't be hit again
			Brush_RemoveFromList( b2 );
			Brush_AddToList( b2, &selected_brushes );
	
			n = Brush_Clone( b2 );
			Brush_AddToList( n, &active_brushes );
			Entity_LinkBrush( e, n );
			Brush_Build( n );
			Brush_Move( b2, delta, true );
		}
	
	}
	Sys_UpdateWindows( W_ALL );
#endif
}
示例#20
0
/*
 =======================================================================================================================
    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;
}
示例#21
0
entity_t *Entity_PostParse(entity_t *ent, brush_t *pList)
{
    bool		has_brushes;
    eclass_t	*e;
    brush_t		*b;
    idVec3		mins, maxs, zero;
    idBounds bo;

    zero.Zero();

    Entity_SetCurveData( ent );

    if (ent->brushes.onext == &ent->brushes)
    {
        has_brushes = false;
    }
    else
    {
        has_brushes = true;
    }

    bool needsOrigin = !GetVectorForKey(ent, "origin", ent->origin);
    const char	*pModel = ValueForKey(ent, "model");

    const char *cp = ValueForKey(ent, "classname");

    if (strlen(cp))
    {
        e = Eclass_ForName(cp, has_brushes);
    }
    else
    {
        const char *cp2 = ValueForKey(ent, "name");
        if (strlen(cp2))
        {
            char buff[1024];
            strcpy(buff, cp2);
            int len = strlen(buff);
            while ((isdigit(buff[len-1]) || buff[len-1] == '_') && len > 0)
            {
                buff[len-1] = '\0';
                len--;
            }
            e = Eclass_ForName(buff, has_brushes);
            SetKeyValue(ent, "classname", buff, false);
        }
        else
        {
            e = Eclass_ForName("", has_brushes);
        }
    }

    idStr str;

    if (e->defArgs.GetString("model", "", str) && e->entityModel == NULL)
    {
        e->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &e->defArgs );
    }

    ent->eclass = e;

    bool hasModel = EntityHasModel(ent);

    if (hasModel)
    {
        ent->eclass->defArgs.GetString("model", "", str);
        if (str.Length())
        {
            hasModel = false;
            ent->epairs.Delete("model");
        }
    }

    if (e->nShowFlags & ECLASS_WORLDSPAWN)
    {
        ent->origin.Zero();
        needsOrigin = false;
        ent->epairs.Delete( "model" );
    }
    else if (e->nShowFlags & ECLASS_LIGHT)
    {
        if (GetVectorForKey(ent, "light_origin", ent->lightOrigin))
        {
            GetMatrixForKey(ent, "light_rotation", ent->lightRotation);
            ent->trackLightOrigin = true;
        }
        else if (hasModel)
        {
            SetKeyValue(ent, "light_origin", ValueForKey(ent, "origin"));
            ent->lightOrigin = ent->origin;
            if (GetMatrixForKey(ent, "rotation", ent->lightRotation))
            {
                SetKeyValue(ent, "light_rotation", ValueForKey(ent, "rotation"));
            }
            ent->trackLightOrigin = true;
        }
    }
    else if ( e->nShowFlags & ECLASS_ENV )
    {
        // need to create an origin from the bones here
        idVec3 org;
        idAngles ang;
        bo.Clear();
        bool hasBody = false;
        const idKeyValue *arg = ent->epairs.MatchPrefix( "body ", NULL );
        while ( arg )
        {
            sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll );
            bo.AddPoint( org );
            arg = ent->epairs.MatchPrefix( "body ", arg );
            hasBody = true;
        }
        if (hasBody)
        {
            ent->origin = bo.GetCenter();
        }
    }

    if (e->fixedsize || hasModel)  			// fixed size entity
    {
        if (ent->brushes.onext != &ent->brushes)
        {
            for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext)
            {
                b->entityModel = true;
            }
        }

        if (hasModel)
        {
            // model entity
            idRenderModel *modelHandle = renderModelManager->FindModel( pModel );

            if ( dynamic_cast<idRenderModelPrt*>( modelHandle ) || dynamic_cast<idRenderModelLiquid*>( modelHandle ) )
            {
                bo.Zero();
                bo.ExpandSelf( 12.0f );
            }
            else
            {
                bo = modelHandle->Bounds( NULL );
            }

            VectorCopy(bo[0], mins);
            VectorCopy(bo[1], maxs);
            for (int i = 0; i < 3; i++)
            {
                if (mins[i] == maxs[i])
                {
                    mins[i]--;
                    maxs[i]++;
                }
            }
            VectorAdd(mins, ent->origin, mins);
            VectorAdd(maxs, ent->origin, maxs);
            b = Brush_Create(mins, maxs, &e->texdef);
            b->modelHandle = modelHandle;

            float		yaw = 0;
            bool		convertAngles = GetFloatForKey(ent, "angle", &yaw);
            extern void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild);
            extern void Brush_Rotate(brush_t *b, idVec3 rot, idVec3 origin, bool bBuild);

            if (convertAngles)
            {
                idVec3	rot(0, 0, yaw);
                Brush_Rotate(b, rot, ent->origin, false);
            }

            if (GetMatrixForKey(ent, "rotation", ent->rotation))
            {
                idBounds bo2;
                bo2.FromTransformedBounds(bo, ent->origin, ent->rotation);
                b->owner = ent;
                Brush_Resize(b, bo2[0], bo2[1]);
            }
            Entity_LinkBrush(ent, b);
        }

        if (!hasModel || (ent->eclass->nShowFlags & ECLASS_LIGHT && hasModel))
        {
            // create a custom brush
            if (ent->trackLightOrigin)
            {
                mins = e->mins + ent->lightOrigin;
                maxs = e->maxs + ent->lightOrigin;
            }
            else
            {
                mins = e->mins + ent->origin;
                maxs = e->maxs + ent->origin;
            }

            b = Brush_Create(mins, maxs, &e->texdef);
            GetMatrixForKey(ent, "rotation", ent->rotation);
            Entity_LinkBrush(ent, b);
            b->trackLightOrigin = ent->trackLightOrigin;
            if ( e->texdef.name == NULL )
            {
                brushprimit_texdef_t bp;
                texdef_t td;
                td.SetName( ent->eclass->defMaterial );
                Brush_SetTexture( b, &td, &bp, false );
            }
        }
    }
    else  	// brush entity
    {
        if (ent->brushes.next == &ent->brushes)
        {
            printf("Warning: Brush entity with no brushes\n");
        }

        if (!needsOrigin)
        {
            idStr cn = ValueForKey(ent, "classname");
            idStr name = ValueForKey(ent, "name");
            idStr model = ValueForKey(ent, "model");
            if (cn.Icmp("func_static") == 0)
            {
                if (name.Icmp(model) == 0)
                {
                    needsOrigin = true;
                }
            }
        }

        if (needsOrigin)
        {
            idVec3	mins, maxs, mid;
            int		i;
            char	text[32];
            mins[0] = mins[1] = mins[2] = 999999;
            maxs[0] = maxs[1] = maxs[2] = -999999;

            // add in the origin
            for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext)
            {
                Brush_Build(b, true, false, false);
                for (i = 0; i < 3; i++)
                {
                    if (b->mins[i] < mins[i])
                    {
                        mins[i] = b->mins[i];
                    }

                    if (b->maxs[i] > maxs[i])
                    {
                        maxs[i] = b->maxs[i];
                    }
                }
            }

            for (i = 0; i < 3; i++)
            {
                ent->origin[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
            }

            sprintf(text, "%i %i %i", (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
            SetKeyValue(ent, "origin", text);
        }

        if (!(e->nShowFlags & ECLASS_WORLDSPAWN))
        {
            if (e->defArgs.FindKey("model") == NULL && (pModel == NULL || (pModel && strlen(pModel) == 0)))
            {
                SetKeyValue(ent, "model", ValueForKey(ent, "name"));
            }
        }
        else
        {
            DeleteKey(ent, "origin");
        }
    }

    // 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;
        }
    }

    FixFloats(&ent->epairs);

    return ent;

}
示例#22
0
//
//================
//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();

}
示例#23
0
//
// =======================================================================================================================
//    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();
}
示例#24
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);
}
示例#25
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;
}
示例#26
0
/*	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);
}
示例#27
0
/*
============
Select_Clone

Creates an exact duplicate of the selection in place, then moves
the selected brushes off of their old positions
============
*/
void Select_Clone (void)
{
	brush_t		*b, *b2, *n, *next, *next2;
	vec3_t		delta;
	entity_t	*e;

	g_qeglobals.d_workcount++;
	g_qeglobals.d_select_mode = sel_brush;

	delta[0] = g_qeglobals.d_gridsize;
	delta[1] = g_qeglobals.d_gridsize;
	delta[2] = 0;

	for (b=selected_brushes.next ; b != &selected_brushes ; b=next)
	{
		next = b->next;
		// if the brush is a world brush, handle simply
		if (b->owner == world_entity)
		{
			n = Brush_Clone (b);
			Brush_AddToList (n, &active_brushes);
			Entity_LinkBrush (world_entity, n);
			Brush_Build( n );
			Brush_Move (b, delta);
			continue;
		}

		e = Entity_Clone (b->owner);
		// clear the target / targetname
		DeleteKey (e, "target");
		DeleteKey (e, "targetname");

		// if the brush is a fixed size entity, create a new entity
		if (b->owner->eclass->fixedsize)
		{
			n = Brush_Clone (b);
			Brush_AddToList (n, &active_brushes);
			Entity_LinkBrush (e, n);
			Brush_Build( n );
			Brush_Move (b, delta);
			continue;
		}
        
		// brush is a complex entity, grab all the other ones now

		next = &selected_brushes;

		for ( b2 = b ; b2 != &selected_brushes ; b2=next2)
		{
			next2 = b2->next;
			if (b2->owner != b->owner)
			{
				if (next == &selected_brushes)
					next = b2;
				continue;
			}

			// move b2 to the start of selected_brushes,
			// so it won't be hit again
			Brush_RemoveFromList (b2);
			Brush_AddToList (b2, &selected_brushes);
			
			n = Brush_Clone (b2);
			Brush_AddToList (n, &active_brushes);
			Entity_LinkBrush (e, n);
			Brush_Build( n );
			Brush_Move (b2, delta);
		}

	}
	Sys_UpdateWindows (W_ALL);
}