select.cpp

来自「quake3工具源码。包括生成bsp文件」· C++ 代码 · 共 1,712 行 · 第 1/3 页

CPP
1,712
字号
// select.c
#include "stdafx.h"
#include "qe3.h"


// externs
CPtrArray g_SelectedFaces;
CPtrArray g_SelectedFaceBrushes;
CPtrArray& g_ptrSelectedFaces = g_SelectedFaces;
CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes;

/*
===========
Test_Ray
===========
*/
#define	DIST_START	999999
trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags)
{
	brush_t	*brush;
	face_t	*face;
	float	dist;
	trace_t	t;

	memset (&t, 0, sizeof(t));
	t.dist = DIST_START;

	if (flags & SF_CYCLE)
	{
		CPtrArray array;
		brush_t *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL;
		Select_Deselect();

		// go through active brushes and accumulate all "hit" brushes
		for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
		{
			//if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
			//  continue;
		 
			if (FilterBrush (brush))
				continue;

			if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
				continue;

			//if (!g_bShowPatchBounds && brush->patchBrush)
			//  continue;

			face = Brush_Ray (origin, dir, brush, &dist);

			if (face)
				array.Add(brush);
		}

		int nSize = array.GetSize();
		if (nSize > 0)
		{
			bool bFound = false;
			for (int i = 0; i < nSize; i++)
			{
				brush_t *b = reinterpret_cast<brush_t*>(array.GetAt(i));
				// did we hit the last one selected yet ?
				if (b == pToSelect)
				{
					// yes we want to select the next one in the list 
					int n = (i > 0) ? i-1 : nSize-1;
					pToSelect = reinterpret_cast<brush_t*>(array.GetAt(n));
					bFound = true;
					break;
				}
			}
			if (!bFound)
				pToSelect = reinterpret_cast<brush_t*>(array.GetAt(0));
		}
		if (pToSelect)
		{
			face = Brush_Ray (origin, dir, pToSelect, &dist);
			t.dist = dist;
			t.brush = pToSelect;
			t.face = face;
			t.selected = false;
			return t;
		}
	}

	if (! (flags & SF_SELECTED_ONLY) )
	{
		for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
		{
			if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
				continue;
			
			if (FilterBrush (brush))
				continue;

			if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
				continue;

			//if (!g_bShowPatchBounds && brush->patchBrush)
			//  continue;

			face = Brush_Ray (origin, dir, brush, &dist);
			if (dist > 0 && dist < t.dist)
			{
				t.dist = dist;
				t.brush = brush;
				t.face = face;
				t.selected = false;
			}
		}
	}


	for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
	{
		if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
			continue;

		if (FilterBrush (brush))
			continue;

		if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
			continue;

		face = Brush_Ray (origin, dir, brush, &dist);
		if (dist > 0 && dist < t.dist)
		{
			t.dist = dist;
			t.brush = brush;
			t.face = face;
			t.selected = true;
		}
	}

	// if entites first, but didn't find any, check regular

	if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL)
		return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST);

	return t;

}


/*
============
Select_Brush

============
*/
void Select_Brush (brush_t *brush, bool bComplete, bool bStatus)
{
	brush_t	*b;
	entity_t	*e;

  g_ptrSelectedFaces.RemoveAll();
  g_ptrSelectedFaceBrushes.RemoveAll();
	//selected_face = NULL;
	if (g_qeglobals.d_select_count < 2)
		g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
	g_qeglobals.d_select_count++;

  //if (brush->patchBrush)
  //  Patch_Select(brush->nPatchID);

	e = brush->owner;
	if (e)
	{
		// select complete entity on first click
		if (e != world_entity && bComplete == true)
		{
			for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
				if (b->owner == e)
					goto singleselect;
			for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
			{
        Brush_RemoveFromList (b);
				Brush_AddToList (b, &selected_brushes);
			}
		}
		else
		{
singleselect:
			Brush_RemoveFromList (brush);
			Brush_AddToList (brush, &selected_brushes);
      UpdateSurfaceDialog();
      UpdatePatchInspector();
		}

		if (e->eclass)
		{
			UpdateEntitySel(brush->owner->eclass);
		}
	}
  if (bStatus)
  {
    vec3_t vMin, vMax, vSize;
	  Select_GetBounds (vMin, vMax);
    VectorSubtract(vMax, vMin, vSize);
    CString strStatus;
    strStatus.Format("Selection X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
    g_pParentWnd->SetStatusText(2, strStatus);
  }
}


/*
============
Select_Ray

If the origin is inside a brush, that brush will be ignored.
============
*/
void Select_Ray (vec3_t origin, vec3_t dir, int flags)
{
	trace_t	t;

	t = Test_Ray (origin, dir, flags);
	if (!t.brush)
		return;

	if (flags == SF_SINGLEFACE)
	{
		int nCount = g_SelectedFaces.GetSize();
		bool bOk = true;
		for (int i = 0; i < nCount; i++)
		{
			if (t.face == reinterpret_cast<face_t*>(g_SelectedFaces.GetAt(i)))
			{
				bOk = false;
				// need to move remove i'th entry
				g_SelectedFaces.RemoveAt(i, 1);
				g_SelectedFaceBrushes.RemoveAt(i, 1);
			}
		}
		if (bOk)
		{
			g_SelectedFaces.Add(t.face);
			g_SelectedFaceBrushes.Add(t.brush);
		}
		//selected_face = t.face;
		//selected_face_brush = t.brush;
		Sys_UpdateWindows (W_ALL);
		g_qeglobals.d_select_mode = sel_brush;
		// Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture
		brushprimit_texdef_t brushprimit_texdef;
		ConvertTexMatWithQTexture ( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL );
		Texture_SetTexture ( &t.face->texdef, &brushprimit_texdef, false, GETPLUGINTEXDEF(t.face), false );
		UpdateSurfaceDialog();
		return;
	}

	// move the brush to the other list

 	g_qeglobals.d_select_mode = sel_brush;

	if (t.selected)
	{		
		Brush_RemoveFromList (t.brush);
		Brush_AddToList (t.brush, &active_brushes);
		UpdatePatchInspector();
	} 
	else
	{
		Select_Brush (t.brush, !(GetKeyState(VK_MENU) & 0x8000));
	}

	Sys_UpdateWindows (W_ALL);
}


void Select_Delete (void)
{
	brush_t	*brush;

  g_ptrSelectedFaces.RemoveAll();
  g_ptrSelectedFaceBrushes.RemoveAll();
	//selected_face = NULL;
	
  g_qeglobals.d_select_mode = sel_brush;

	g_qeglobals.d_select_count = 0;
	g_qeglobals.d_num_move_points = 0;
	while (selected_brushes.next != &selected_brushes)
	{
		brush = selected_brushes.next;
    if (brush->patchBrush)
    {
      //Patch_Delete(brush->nPatchID);
      Patch_Delete(brush->pPatch);
    }
		Brush_Free (brush);
	}

	// FIXME: remove any entities with no brushes

	Sys_UpdateWindows (W_ALL);
}

void Select_Deselect (bool bDeselectFaces)
{
	brush_t	*b;

  Patch_Deselect();

  g_pParentWnd->ActiveXY()->UndoClear();

  g_qeglobals.d_workcount++;
	g_qeglobals.d_select_count = 0;
	g_qeglobals.d_num_move_points = 0;
	b = selected_brushes.next;

	if (b == &selected_brushes)
	{
		if (bDeselectFaces)
		{
			g_ptrSelectedFaces.RemoveAll();
      g_ptrSelectedFaceBrushes.RemoveAll();
      //selected_face = NULL;
		}
 		Sys_UpdateWindows (W_ALL);
		return;
	}

  if (bDeselectFaces)
  {
  	g_ptrSelectedFaces.RemoveAll();
    g_ptrSelectedFaceBrushes.RemoveAll();
	  //selected_face = NULL;
  }

	g_qeglobals.d_select_mode = sel_brush;

	// grab top / bottom height for new brushes
	if (b->mins[2] < b->maxs[2])
	{
		g_qeglobals.d_new_brush_bottom_z = b->mins[2];
		g_qeglobals.d_new_brush_top_z = b->maxs[2];
	}

	selected_brushes.next->prev = &active_brushes;
	selected_brushes.prev->next = active_brushes.next;
	active_brushes.next->prev = selected_brushes.prev;
	active_brushes.next = selected_brushes.next;
	selected_brushes.prev = selected_brushes.next = &selected_brushes;	

	Sys_UpdateWindows (W_ALL);
}

/*
============
Select_Move
============
*/
void Select_Move (vec3_t delta, bool bSnap)
{
	brush_t	*b;
  
 
// actually move the selected brushes
	for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
		Brush_Move (b, delta, bSnap);

  vec3_t vMin, vMax;
	Select_GetBounds (vMin, vMax);
  CString strStatus;
  strStatus.Format("Origin X:: %.1f  Y:: %.1f  Z:: %.1f", vMin[0], vMax[1], vMax[2]);
  g_pParentWnd->SetStatusText(2, strStatus);

//	Sys_UpdateWindows (W_ALL);
}

/*
============
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_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, true);
		}

	}
	Sys_UpdateWindows (W_ALL);
#endif
}



/*
============
Select_SetTexture
Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping
Timo :	brush primitive texturing
		the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes )
Timo :  texture plugin, added an IPluginTexdef* parameter
		must be casted to an IPluginTexdef!
		if not NULL, get ->Copy() of it into each face or brush ( and remember to hook )
		if NULL, means we have no information, ask for a default
============
*/
void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef )
{
	brush_t	*b;
	int nCount = g_ptrSelectedFaces.GetSize();
	if (nCount > 0)
	{
		Undo_Start("set face textures");
		ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize());
		for (int i = 0; i < nCount; i++)
		{
			face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
			brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
			Undo_AddBrush(selBrush);
			SetFaceTexdef (selBrush, selFace, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>(pPlugTexdef) );
			Brush_Build(selBrush, bFitScale);
			Undo_EndBrush(selBrush);
		}
		Undo_End();
	}
	else if (selected_brushes.next != &selected_brushes)
	{
		Undo_Start("set brush textures");
		for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
			if (!b->owner->eclass->fixedsize)
			{
				Undo_AddBrush(b);
				Brush_SetTexture (b, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>(pPlugTexdef) );
				Undo_EndBrush(b);
			}
		Undo_End();
	}
	Sys_UpdateWindows (W_ALL);
}


/*
================================================================

  TRANSFORMATIONS

================================================================
*/

void Select_GetBounds (vec3_t mins, vec3_t maxs)
{
	brush_t	*b;
	int		i;

	for (i=0 ; i<3 ; i++)
	{
		mins[i] = 99999;
		maxs[i] = -99999;
	}

	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
		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];
		}
}


void Select_GetTrueMid (vec3_t mid)
{
	vec3_t	mins, maxs;
	Select_GetBounds (mins, maxs);

  for (int i=0 ; i<3 ; i++)
    mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
}


void Select_GetMid (vec3_t mid)
{
	vec3_t	mins, maxs;
	int		i;

  if (g_PrefsDlg.m_bNoClamp)
  {
    Select_GetTrueMid(mid);
    return;
  }

  Select_GetBounds (mins, maxs);

  for (i=0 ; i<3 ; i++)
		mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize );

}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?