diff --git a/include/iselectiontest.h b/include/iselectiontest.h index 4b15c2eb22..e50e1585db 100644 --- a/include/iselectiontest.h +++ b/include/iselectiontest.h @@ -271,6 +271,12 @@ class Selector */ virtual void addIntersection(const SelectionIntersection& intersection) = 0; + // Returns true if no selectable has been chosen + virtual bool empty() const = 0; + + // Iterate over every selectable in the pool + virtual void foreachSelectable(const std::function& functor) = 0; + /// Add a selectable object and immediately commit it with a null intersection void addWithNullIntersection(ISelectable& selectable) { diff --git a/libs/selection/EntitiesFirstSelector.h b/libs/selection/EntitiesFirstSelector.h index 22223e2459..344a2418e0 100644 --- a/libs/selection/EntitiesFirstSelector.h +++ b/libs/selection/EntitiesFirstSelector.h @@ -89,14 +89,14 @@ class EntitiesFirstSelector : _currentSelectables.emplace(selectable, result); } - bool empty() const + bool empty() const override { return _entityPool.empty() && _primitivePool.empty(); } // Visit each selectable, entities first, then primitives - void foreachSelectable(const std::function& functor) - { + void foreachSelectable(const std::function& functor) override + { for (const auto& [_, selectable] : _entityPool) { functor(selectable); diff --git a/libs/selection/OccludeSelector.h b/libs/selection/OccludeSelector.h index a67f205df4..bed9d903f5 100644 --- a/libs/selection/OccludeSelector.h +++ b/libs/selection/OccludeSelector.h @@ -20,10 +20,10 @@ class OccludeSelector : _occluded = false; } - void pushSelectable(ISelectable& selectable) {} - void popSelectable() {} + void pushSelectable(ISelectable& selectable) override {} + void popSelectable() override {} - void addIntersection(const SelectionIntersection& intersection) + void addIntersection(const SelectionIntersection& intersection) override { if (intersection.isCloserThan(_bestIntersection)) { @@ -31,6 +31,14 @@ class OccludeSelector : _occluded = true; } } + + bool empty() const override + { + return true; + } + + void foreachSelectable(const std::function& functor) override + {} }; } // namespace diff --git a/libs/selection/SelectionPool.h b/libs/selection/SelectionPool.h index 7465c9efbe..0e82b6dbf7 100644 --- a/libs/selection/SelectionPool.h +++ b/libs/selection/SelectionPool.h @@ -121,10 +121,18 @@ class SelectionPool : return _pool.end(); } - bool empty() + bool empty() const override { return _pool.empty(); } + + void foreachSelectable(const std::function& functor) override + { + for (const auto& [_, selectable] : _pool) + { + functor(selectable); + } + } }; } diff --git a/libs/selection/SingleItemSelector.h b/libs/selection/SingleItemSelector.h index b499bb3f95..8d82871954 100644 --- a/libs/selection/SingleItemSelector.h +++ b/libs/selection/SingleItemSelector.h @@ -60,6 +60,19 @@ class SingleItemSelector : { return _selectable; } + + bool empty() const override + { + return !hasValidSelectable(); + } + + void foreachSelectable(const std::function& functor) override + { + if (!empty()) + { + functor(_selectable); + } + } }; } diff --git a/radiantcore/selection/BestSelector.h b/radiantcore/selection/BestSelector.h index 1c2a5c55df..78e1a84559 100644 --- a/radiantcore/selection/BestSelector.h +++ b/radiantcore/selection/BestSelector.h @@ -25,7 +25,8 @@ class BestSelector : std::list _bestSelectables; public: - BestSelector() + BestSelector() : + _selectable(nullptr) {} void pushSelectable(ISelectable& selectable) override @@ -60,6 +61,19 @@ class BestSelector : { return _bestSelectables; } + + bool empty() const override + { + return _bestSelectables.empty(); + } + + void foreachSelectable(const std::function& functor) override + { + for (auto selectable : _bestSelectables) + { + functor(selectable); + } + } }; } diff --git a/radiantcore/selection/RadiantSelectionSystem.cpp b/radiantcore/selection/RadiantSelectionSystem.cpp index dba5e6c4a6..d052272342 100644 --- a/radiantcore/selection/RadiantSelectionSystem.cpp +++ b/radiantcore/selection/RadiantSelectionSystem.cpp @@ -128,7 +128,6 @@ void RadiantSelectionSystem::testSelectScene(SelectablesList& targetList, Select { // The (temporary) storage pool SelectionPool selector; - SelectionPool sel2; switch(mode) { @@ -144,52 +143,16 @@ void RadiantSelectionSystem::testSelectScene(SelectablesList& targetList, Select case SelectionMode::Primitive: { -#if 1 - // We have an orthoview, here, sorting entities before primitives + // Sort entities before primitives if required, by referencing the correct selector EntitiesFirstSelector sortedPool; - AnySelector anyTester(sortedPool, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, anyTester); + auto& targetPool = !view.fill() && higherEntitySelectionPriority() ? + static_cast(sortedPool) : selector; - //auto tester = createSceneSelectionTester(mode); - //tester->testSelectScene(view, test, selector); - - sortedPool.foreachSelectable([&](ISelectable* s) { targetList.push_back(s); }); -#else - // Do we have a camera view (filled rendering?) - if (view.fill() || !higherEntitySelectionPriority()) - { - // Test for any visible elements (primitives, entities), but don't select child primitives - AnySelector anyTester(selector, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, anyTester); - } - else - { - // First, obtain all the selectable entities - EntitySelector entityTester(selector, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, entityTester); - - // Now retrieve all the selectable primitives - PrimitiveSelector primitiveTester(sel2, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, primitiveTester); - } - - // Add the first selection crop to the target vector - std::for_each(selector.begin(), selector.end(), [&](const auto& p) { targetList.push_back(p.second); }); + auto tester = createSceneSelectionTester(mode); + tester->testSelectScene(view, test, targetPool); - // Add the secondary crop to the vector (if it has any entries) - for (SelectionPool::const_iterator i = sel2.begin(); i != sel2.end(); ++i) { - // Check for duplicates - SelectablesList::iterator j; - for (j = targetList.begin(); j != targetList.end(); ++j) { - if (*j == i->second) break; - } - // Insert if not yet in the list - if (j == targetList.end()) { - targetList.push_back(i->second); - } - } -#endif + targetPool.foreachSelectable([&](ISelectable* s) { targetList.push_back(s); }); } break; @@ -222,7 +185,7 @@ void RadiantSelectionSystem::testSelectScene(SelectablesList& targetList, Select std::for_each(selector.begin(), selector.end(), [&](const auto& p) { targetList.push_back(p.second); }); } break; - } // switch + } } /* greebo: This is true if nothing is selected (either in component mode or in primitive mode) diff --git a/radiantcore/selection/SceneSelectionTesters.cpp b/radiantcore/selection/SceneSelectionTesters.cpp index cd350c37dc..b298897853 100644 --- a/radiantcore/selection/SceneSelectionTesters.cpp +++ b/radiantcore/selection/SceneSelectionTesters.cpp @@ -1,66 +1,15 @@ #include "SceneSelectionTesters.h" #include "iscenegraph.h" -#include "registry/registry.h" #include "SelectionTestWalkers.h" -#include "selection/SelectionPool.h" namespace selection { void PrimitiveSelectionTester::testSelectScene(const VolumeTest& view, SelectionTest& test, Selector& selector) { - // Cameras don't sort entities higher - if (view.fill() || !higherEntitySelectionPriority()) - { - // Test for any visible elements (primitives, entities), but don't select child primitives - AnySelector anyTester(selector, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, anyTester); - return; - } - - // We have an orthoview, select entities first - SelectionPool entityPool; - SelectionPool primitivePool; - - // First, obtain all the selectable entities - EntitySelector entityTester(entityPool, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, entityTester); - - // Now retrieve all the selectable primitives - PrimitiveSelector primitiveTester(primitivePool, test); - GlobalSceneGraph().foreachVisibleNodeInVolume(view, primitiveTester); - - // Transfer the items of both pools to the target selector, entities first - for (const auto& [intersection, selectable] : entityPool) - { - selector.pushSelectable(*selectable); - selector.addIntersection(intersection); - selector.popSelectable(); - } - - for (const auto& [intersection, selectable] : primitivePool) - { - // Check for duplicates - SelectionPool::const_iterator existing; - - for (existing = entityPool.begin(); existing != entityPool.end(); ++existing) - { - if (existing->second == selectable) break; - } - - if (existing == entityPool.end()) - { - selector.pushSelectable(*selectable); - selector.addIntersection(intersection); - selector.popSelectable(); - } - } -} - -bool PrimitiveSelectionTester::higherEntitySelectionPriority() const -{ - return registry::getValue(RKEY_HIGHER_ENTITY_PRIORITY); + AnySelector anyTester(selector, test); + GlobalSceneGraph().foreachVisibleNodeInVolume(view, anyTester); } void EntitySelectionTester::testSelectScene(const VolumeTest& view, SelectionTest& test, Selector& selector) diff --git a/radiantcore/selection/SceneSelectionTesters.h b/radiantcore/selection/SceneSelectionTesters.h index 2869d79b02..b3e4692556 100644 --- a/radiantcore/selection/SceneSelectionTesters.h +++ b/radiantcore/selection/SceneSelectionTesters.h @@ -6,16 +6,13 @@ namespace selection { /** - * Tests entities and primitives in the scene, entities sorted first + * Tests entities and worldspawn primitives in the scene */ class PrimitiveSelectionTester : public ISceneSelectionTester { public: void testSelectScene(const VolumeTest& view, SelectionTest& test, Selector& selector) override; - -private: - bool higherEntitySelectionPriority() const; }; /**