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 + -
显示快捷键?