mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2024-11-10 07:11:54 +00:00
- Added "select inside" and "select touching"
Both functions now work with multiple selectionbrushes, allowing complex selection operations. - Added entries for the selectionfunctions in "Edit" and the main toolbar. git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/trunk@113 8a3a26a2-13c4-0310-b231-cf6edde360e5
This commit is contained in:
parent
049119a99d
commit
8d4bd599b6
5 changed files with 200 additions and 3 deletions
6
CHANGES
6
CHANGES
|
@ -1,6 +1,12 @@
|
|||
This is the changelog for developers, != changelog for the end user
|
||||
that we distribute with the binaries. (see changelog)
|
||||
|
||||
07/10/2006
|
||||
- Added "select inside" and "select touching"
|
||||
Both functions now work with multiple selectionbrushes, allowing complex
|
||||
selection operations.
|
||||
- Added entries for the selectionfunctions in "Edit" and the main toolbar.
|
||||
|
||||
06/10/2006
|
||||
namespace
|
||||
- Changed ETB not to show any texture if a tag search doesn't match anything (Shaderman)
|
||||
|
|
2
TODO
2
TODO
|
@ -19,7 +19,6 @@ FEATURES
|
|||
|
||||
- paint-select or equivalent (e.g. area-selection with occlusion)
|
||||
- select-complete-tall or equivalent (e.g. subtract-from-selection modifier key)
|
||||
- need some equivalent to select-inside.
|
||||
- texture pane names are often illegible, becuase 1. they are long and overlap each other and 2. they overlap the outline rectangles around the images themselves.
|
||||
- texture sizes sometimes vary wildly. It would be nice to find a way to normalize their display size so that very big textures are shrunk a little, and very small textures are blown-up a little.
|
||||
|
||||
|
@ -134,7 +133,6 @@ Selection: Add shear manipulator?
|
|||
Textures Window: Improve texture-manipulation and texture-browsing tools.
|
||||
Undo: make selections undoable?
|
||||
Win32 Installer: Automatically upgrade existing installation.
|
||||
Selection: grow-brush-selection feature - select all neighbouring brushes
|
||||
General: refactor game-specific hacks to be parameterised by .game file
|
||||
Patch: Overlays, Bend Mode, Thicken.
|
||||
Brush: Add brush-specific plugin API.
|
||||
|
|
|
@ -1980,6 +1980,8 @@ GtkMenuItem* create_edit_menu()
|
|||
menu_separator(menu);
|
||||
create_menu_item_with_mnemonic(menu, "C_lear Selection", "UnSelectSelection");
|
||||
create_menu_item_with_mnemonic(menu, "_Invert Selection", "InvertSelection");
|
||||
create_menu_item_with_mnemonic(menu, "Select i_nside", "SelectInside");
|
||||
create_menu_item_with_mnemonic(menu, "Select _touching", "SelectTouching");
|
||||
|
||||
GtkMenu* convert_menu = create_sub_menu_with_mnemonic(menu, "E_xpand Selection");
|
||||
create_menu_item_with_mnemonic(convert_menu, "To Whole _Entities", "ExpandSelectionToEntities");
|
||||
|
@ -2398,6 +2400,12 @@ void RotateFlip_constructToolbar(GtkToolbar* toolbar)
|
|||
toolbar_append_button(toolbar, "z-axis Rotate", "brush_rotatez.bmp", "RotateSelectionZ");
|
||||
}
|
||||
|
||||
void Select_constructToolbar(GtkToolbar* toolbar)
|
||||
{
|
||||
toolbar_append_button(toolbar, "Select touching", "selection_selecttouching.bmp", "SelectTouching");
|
||||
toolbar_append_button(toolbar, "Select inside", "selection_selectinside.bmp", "SelectInside");
|
||||
}
|
||||
|
||||
void CSG_constructToolbar(GtkToolbar* toolbar)
|
||||
{
|
||||
toolbar_append_button(toolbar, "CSG Subtract", "selection_csgsubtract.bmp", "CSGSubtract");
|
||||
|
@ -2449,6 +2457,10 @@ GtkToolbar* create_main_toolbar(MainFrame::EViewStyle style)
|
|||
|
||||
gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
|
||||
|
||||
Select_constructToolbar(toolbar);
|
||||
|
||||
gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
|
||||
|
||||
CSG_constructToolbar(toolbar);
|
||||
|
||||
gtk_toolbar_append_space (GTK_TOOLBAR (toolbar));
|
||||
|
@ -3344,6 +3356,8 @@ void MainFrame_Construct()
|
|||
GlobalCommands_insert("ParentSelection", FreeCaller<Scene_parentSelected>());
|
||||
GlobalCommands_insert("UnSelectSelection", FreeCaller<Selection_Deselect>(), Accelerator(GDK_Escape));
|
||||
GlobalCommands_insert("InvertSelection", FreeCaller<Select_Invert>(), Accelerator('I'));
|
||||
GlobalCommands_insert("SelectInside", FreeCaller<Select_Inside>());
|
||||
GlobalCommands_insert("SelectTouching", FreeCaller<Select_Touching>());
|
||||
GlobalCommands_insert("ExpandSelectionToEntities", FreeCaller<Scene_ExpandSelectionToEntities>(), Accelerator('E', (GdkModifierType)(GDK_MOD1_MASK|GDK_CONTROL_MASK)));
|
||||
GlobalCommands_insert("Preferences", FreeCaller<PreferencesDialog_showDialog>(), Accelerator('P'));
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "gtkutil/dialog.h"
|
||||
#include "gtkutil/widget.h"
|
||||
#include "brushmanip.h"
|
||||
#include "brush.h"
|
||||
#include "patchmanip.h"
|
||||
#include "patchdialog.h"
|
||||
#include "selection.h"
|
||||
|
@ -52,6 +53,172 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
select_workzone_t g_select_workzone;
|
||||
|
||||
|
||||
/**
|
||||
Loops over all selected brushes and stores their
|
||||
world AABBs in the specified array.
|
||||
*/
|
||||
class CollectSelectedBrushesBounds : public SelectionSystem::Visitor
|
||||
{
|
||||
AABB* m_bounds; // array of AABBs
|
||||
Unsigned m_max; // max AABB-elements in array
|
||||
Unsigned& m_count;// count of valid AABBs stored in array
|
||||
|
||||
public:
|
||||
CollectSelectedBrushesBounds(AABB* bounds, Unsigned max, Unsigned& count)
|
||||
: m_bounds(bounds),
|
||||
m_max(max),
|
||||
m_count(count)
|
||||
{
|
||||
m_count = 0;
|
||||
}
|
||||
|
||||
void visit(scene::Instance& instance) const
|
||||
{
|
||||
ASSERT_MESSAGE(m_count <= m_max, "Invalid m_count in CollectSelectedBrushesBounds");
|
||||
|
||||
// stop if the array is already full
|
||||
if(m_count == m_max)
|
||||
return;
|
||||
|
||||
Selectable* selectable = Instance_getSelectable(instance);
|
||||
if((selectable != 0)
|
||||
&& instance.isSelected())
|
||||
{
|
||||
// brushes only
|
||||
if(Instance_getBrush(instance) != 0)
|
||||
{
|
||||
m_bounds[m_count] = instance.worldAABB();
|
||||
++m_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Selects all objects that intersect one of the bounding AABBs.
|
||||
The exact intersection-method is specified through TSelectionPolicy
|
||||
*/
|
||||
template<class TSelectionPolicy>
|
||||
class SelectByBounds : public scene::Graph::Walker
|
||||
{
|
||||
AABB* m_aabbs; // selection aabbs
|
||||
Unsigned m_count; // number of aabbs in m_aabbs
|
||||
TSelectionPolicy policy; // type that contains a custom intersection method aabb<->aabb
|
||||
|
||||
public:
|
||||
SelectByBounds(AABB* aabbs, Unsigned count)
|
||||
: m_aabbs(aabbs),
|
||||
m_count(count)
|
||||
{
|
||||
}
|
||||
|
||||
bool pre(const scene::Path& path, scene::Instance& instance) const
|
||||
{
|
||||
Selectable* selectable = Instance_getSelectable(instance);
|
||||
|
||||
// ignore worldspawn
|
||||
Entity* entity = Node_getEntity(path.top());
|
||||
if(entity)
|
||||
{
|
||||
if(string_equal(entity->getKeyValue("classname"), "worldspawn"))
|
||||
return true;
|
||||
}
|
||||
|
||||
if( (path.size() > 1) &&
|
||||
(!path.top().get().isRoot()) &&
|
||||
(selectable != 0)
|
||||
)
|
||||
{
|
||||
for(Unsigned i = 0; i < m_count; ++i)
|
||||
{
|
||||
if(policy.Evaluate(m_aabbs[i], instance))
|
||||
{
|
||||
selectable->setSelected(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
Performs selection operation on the global scenegraph.
|
||||
If delete_bounds_src is true, then the objects which were
|
||||
used as source for the selection aabbs will be deleted.
|
||||
*/
|
||||
static void DoSelection(bool delete_bounds_src = true)
|
||||
{
|
||||
if(GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive)
|
||||
{
|
||||
// we may not need all AABBs since not all selected objects have to be brushes
|
||||
const Unsigned max = (Unsigned)GlobalSelectionSystem().countSelected();
|
||||
AABB* aabbs = new AABB[max];
|
||||
|
||||
Unsigned count;
|
||||
CollectSelectedBrushesBounds collector(aabbs, max, count);
|
||||
GlobalSelectionSystem().foreachSelected(collector);
|
||||
|
||||
// nothing usable in selection
|
||||
if(!count)
|
||||
{
|
||||
delete[] aabbs;
|
||||
return;
|
||||
}
|
||||
|
||||
// delete selected objects
|
||||
if(delete_bounds_src)// see deleteSelection
|
||||
{
|
||||
UndoableCommand undo("deleteSelected");
|
||||
Select_Delete();
|
||||
}
|
||||
|
||||
// select objects with bounds
|
||||
GlobalSceneGraph().traverse(SelectByBounds<TSelectionPolicy>(aabbs, count));
|
||||
|
||||
SceneChangeNotify();
|
||||
delete[] aabbs;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
SelectionPolicy for SelectByBounds
|
||||
Returns true if box and the AABB of instance intersect
|
||||
*/
|
||||
class SelectionPolicy_Touching
|
||||
{
|
||||
public:
|
||||
bool Evaluate(const AABB& box, scene::Instance& instance) const
|
||||
{
|
||||
const AABB& other(instance.worldAABB());
|
||||
for(Unsigned i = 0; i < 3; ++i)
|
||||
{
|
||||
if(fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] + other.extents[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
SelectionPolicy for SelectByBounds
|
||||
Returns true if the AABB of instance is inside box
|
||||
*/
|
||||
class SelectionPolicy_Inside
|
||||
{
|
||||
public:
|
||||
bool Evaluate(const AABB& box, scene::Instance& instance) const
|
||||
{
|
||||
const AABB& other(instance.worldAABB());
|
||||
for(Unsigned i = 0; i < 3; ++i)
|
||||
{
|
||||
if(fabsf(box.origin[i] - other.origin[i]) > (box.extents[i] - other.extents[i]))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class DeleteSelected : public scene::Graph::Walker
|
||||
{
|
||||
mutable bool m_remove;
|
||||
|
@ -73,12 +240,13 @@ public:
|
|||
{
|
||||
m_remove = true;
|
||||
|
||||
return false;
|
||||
return false;// dont traverse into child elements
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void post(const scene::Path& path, scene::Instance& instance) const
|
||||
{
|
||||
|
||||
if(m_removedChild)
|
||||
{
|
||||
m_removedChild = false;
|
||||
|
@ -93,6 +261,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// node should be removed
|
||||
if(m_remove)
|
||||
{
|
||||
if(Node_isEntity(path.parent()) != 0)
|
||||
|
@ -575,7 +744,15 @@ void Select_AllOfType()
|
|||
}
|
||||
}
|
||||
|
||||
void Select_Inside(void)
|
||||
{
|
||||
SelectByBounds<SelectionPolicy_Inside>::DoSelection();
|
||||
}
|
||||
|
||||
void Select_Touching(void)
|
||||
{
|
||||
SelectByBounds<SelectionPolicy_Touching>::DoSelection(false);
|
||||
}
|
||||
|
||||
void Select_FitTexture(float horizontal, float vertical)
|
||||
{
|
||||
|
|
|
@ -29,6 +29,8 @@ void Select_GetMid(Vector3& mid);
|
|||
|
||||
void Select_Delete();
|
||||
void Select_Invert();
|
||||
void Select_Inside();
|
||||
void Select_Touching();
|
||||
void Scene_ExpandSelectionToEntities();
|
||||
|
||||
void Selection_Flipx();
|
||||
|
|
Loading…
Reference in a new issue