]> de.git.xonotic.org Git - xonotic/netradiant.git/commitdiff
- Added "select inside" and "select touching"
authornamespace <namespace>
Sat, 7 Oct 2006 15:08:18 +0000 (15:08 +0000)
committernamespace <namespace>
Sat, 7 Oct 2006 15:08:18 +0000 (15:08 +0000)
  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

CHANGES
TODO
radiant/mainframe.cpp
radiant/select.cpp
radiant/select.h

diff --git a/CHANGES b/CHANGES
index f54a80ec7819c327816aaa6cb76a86e61412bfe0..be96d4199a19fc4105a497b946afcede8ee13ed2 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,12 @@
 This is the changelog for developers, != changelog for the end user 
 that we distribute with the binaries. (see changelog)
 
 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)
 06/10/2006
 namespace
 - Changed ETB not to show any texture if a tag search doesn't match anything (Shaderman)
diff --git a/TODO b/TODO
index d91876ac35fde37d97cc47ab61f801de05041d1e..dcb862f1fec419383394b869eb36af42ade4e356 100644 (file)
--- a/TODO
+++ b/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)
 
 - 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.
 
 - 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.
 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.
 General: refactor game-specific hacks to be parameterised by .game file
 Patch: Overlays, Bend Mode, Thicken.
 Brush: Add brush-specific plugin API.
index 7c8a11810b3f2427e98838944ed1062348c56ca4..47cfca193e70cec8afa70b97d740f92fd1c016e7 100644 (file)
@@ -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");
   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");
 
   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");
 }
 
   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");
 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));
 
 
   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));
   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("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'));
 
   GlobalCommands_insert("ExpandSelectionToEntities", FreeCaller<Scene_ExpandSelectionToEntities>(), Accelerator('E', (GdkModifierType)(GDK_MOD1_MASK|GDK_CONTROL_MASK)));
   GlobalCommands_insert("Preferences", FreeCaller<PreferencesDialog_showDialog>(), Accelerator('P'));
 
index 496d96a45b5200635dfcf2347fa8476d481de738..70e815d138acc9526ac281fe1cc46c36f8bd79b8 100644 (file)
@@ -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 "gtkutil/dialog.h"
 #include "gtkutil/widget.h"
 #include "brushmanip.h"
+#include "brush.h"
 #include "patchmanip.h"
 #include "patchdialog.h"
 #include "selection.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;
 
 
 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;
 class DeleteSelected : public scene::Graph::Walker
 {
   mutable bool m_remove;
@@ -73,12 +240,13 @@ public:
     {
       m_remove = true;
 
     {
       m_remove = true;
 
-      return false;
+      return false;// dont traverse into child elements
     }
     return true;
   }
   void post(const scene::Path& path, scene::Instance& instance) const
   {
     }
     return true;
   }
   void post(const scene::Path& path, scene::Instance& instance) const
   {
+    
     if(m_removedChild)
     {
       m_removedChild = false;
     if(m_removedChild)
     {
       m_removedChild = false;
@@ -93,6 +261,7 @@ public:
       }
     }
 
       }
     }
 
+       // node should be removed
     if(m_remove)
     {
       if(Node_isEntity(path.parent()) != 0)
     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)
 {
 
 void Select_FitTexture(float horizontal, float vertical)
 {
index db71181457d689cd5a3b1a5aaab085dc9e1a3b1b..5a019f7c4d7eb2ae1f61a2ac4aa63207f3fb87ac 100644 (file)
@@ -29,6 +29,8 @@ void Select_GetMid(Vector3& mid);
 
 void Select_Delete();
 void Select_Invert();
 
 void Select_Delete();
 void Select_Invert();
+void Select_Inside();
+void Select_Touching();
 void Scene_ExpandSelectionToEntities();
 
 void Selection_Flipx();
 void Scene_ExpandSelectionToEntities();
 
 void Selection_Flipx();