diff --git a/include/ibrush.h b/include/ibrush.h index 9877b59e9b..fc1f2c7c91 100644 --- a/include/ibrush.h +++ b/include/ibrush.h @@ -90,6 +90,27 @@ class IFace virtual Matrix4 getTexDefMatrix() const = 0; }; +// Plane classification info used by splitting and CSG algorithms +struct BrushSplitType +{ + std::size_t counts[3]; + + BrushSplitType() + { + counts[0] = 0; + counts[1] = 0; + counts[2] = 0; + } + + BrushSplitType& operator+=(const BrushSplitType& other) + { + counts[0] += other.counts[0]; + counts[1] += other.counts[1]; + counts[2] += other.counts[2]; + return *this; + } +}; + // Brush Interface class IBrush { @@ -158,6 +179,9 @@ class IBrush * Q3-compatibility feature, set the detail/structural flag */ virtual void setDetailFlag(DetailFlag newValue) = 0; + + // Classify this brush against the given plane, used by clipper and CSG algorithms + virtual BrushSplitType classifyPlane(const Plane3& plane) const = 0; }; // Forward-declare the Brush object, only accessible from main binary diff --git a/include/iclipper.h b/include/iclipper.h index 8fd7c59a4a..2c2897b021 100644 --- a/include/iclipper.h +++ b/include/iclipper.h @@ -17,22 +17,6 @@ enum PlaneClassification { ePlaneOn = 2, }; -struct BrushSplitType { - std::size_t counts[3]; - - BrushSplitType() { - counts[0] = 0; - counts[1] = 0; - counts[2] = 0; - } - BrushSplitType& operator+=(const BrushSplitType& other) { - counts[0] += other.counts[0]; - counts[1] += other.counts[1]; - counts[2] += other.counts[2]; - return *this; - } -}; - class ClipPoint; const char* const MODULE_CLIPPER("Clipper"); diff --git a/radiant/Makefile.am b/radiant/Makefile.am index 9c3f687be6..a95e46d8d7 100644 --- a/radiant/Makefile.am +++ b/radiant/Makefile.am @@ -53,7 +53,6 @@ darkradiant_SOURCES = main.cpp \ brush/Face.cpp \ brush/TexDef.cpp \ brush/TextureMatrix.cpp \ - brush/csg/BrushByPlaneClipper.cpp \ brush/csg/CSG.cpp \ brush/FacePlane.cpp \ camera/Camera.cpp \ @@ -341,6 +340,8 @@ darkradiant_SOURCES = main.cpp \ map/RenderableAasFile.cpp \ clipper/ClipPoint.cpp \ clipper/Clipper.cpp \ + clipper/SplitAlgorithm.cpp \ + clipper/BrushByPlaneClipper.cpp \ log/Console.cpp \ model/ModelScalePreserver.cpp \ model/ModelExporter.cpp \ diff --git a/radiant/brush/Brush.cpp b/radiant/brush/Brush.cpp index 291c7930e7..75044c53d4 100644 --- a/radiant/brush/Brush.cpp +++ b/radiant/brush/Brush.cpp @@ -216,6 +216,23 @@ void Brush::setDetailFlag(DetailFlag newValue) _detailFlag = newValue; } +BrushSplitType Brush::classifyPlane(const Plane3& plane) const +{ + evaluateBRep(); + + BrushSplitType split; + + for (auto face : *this) + { + if (face->contributes()) + { + split += face->getWinding().classifyPlane(plane); + } + } + + return split; +} + void Brush::evaluateBRep() const { if(m_planeChanged) { m_planeChanged = false; diff --git a/radiant/brush/Brush.h b/radiant/brush/Brush.h index 199b9bc50a..f957840667 100644 --- a/radiant/brush/Brush.h +++ b/radiant/brush/Brush.h @@ -209,6 +209,8 @@ class Brush : DetailFlag getDetailFlag() const; void setDetailFlag(DetailFlag newValue); + BrushSplitType classifyPlane(const Plane3& plane) const override; + void evaluateBRep() const; void transformChanged(); diff --git a/radiant/brush/csg/CSG.cpp b/radiant/brush/csg/CSG.cpp index e4a6b6d2c9..4561a5b549 100644 --- a/radiant/brush/csg/CSG.cpp +++ b/radiant/brush/csg/CSG.cpp @@ -24,8 +24,6 @@ #include "wxutil/dialog/MessageBox.h" #include "wxutil/dialog/MessageBox.h" -#include "BrushByPlaneClipper.h" - namespace brush { namespace algorithm { @@ -123,19 +121,6 @@ void makeRoomForSelectedBrushes(const cmd::ArgumentList& args) { SceneChangeNotify(); } -BrushSplitType Brush_classifyPlane(const Brush& brush, const Plane3& plane) { - brush.evaluateBRep(); - - BrushSplitType split; - for (Brush::const_iterator i(brush.begin()); i != brush.end(); ++i) { - if ((*i)->contributes()) { - split += (*i)->getWinding().classifyPlane(plane); - } - } - - return split; -} - // Returns true if fragments have been inserted into the given ret_fragments list bool Brush_subtract(const BrushNodePtr& brush, const Brush& other, BrushPtrVector& ret_fragments) { @@ -152,7 +137,7 @@ bool Brush_subtract(const BrushNodePtr& brush, const Brush& other, BrushPtrVecto if (!face.contributes()) continue; - BrushSplitType split = Brush_classifyPlane(back->getBrush(), face.plane3()); + BrushSplitType split = back->getBrush().classifyPlane(face.plane3()); if (split.counts[ePlaneFront] != 0 && split.counts[ePlaneBack] != 0) { @@ -468,55 +453,6 @@ void mergeSelectedBrushes(const cmd::ArgumentList& args) SceneChangeNotify(); } -class BrushSetClipPlane : - public SelectionSystem::Visitor -{ - Plane3 _plane; -public: - BrushSetClipPlane(const Plane3& plane) : - _plane(plane) - {} - - virtual ~BrushSetClipPlane() {} - - void visit(const scene::INodePtr& node) const { - BrushNodePtr brush = std::dynamic_pointer_cast(node); - - if (brush != NULL && node->visible()) { - brush->setClipPlane(_plane); - } - } -}; - -/** - * greebo: Sets the "clip plane" of the selected brushes in the scene. - */ -void setBrushClipPlane(const Plane3& plane) { - BrushSetClipPlane walker(plane); - GlobalSelectionSystem().foreachSelected(walker); -} - -/** - * greebo: Splits the selected brushes by the given plane. - */ -void splitBrushesByPlane(const Vector3 planePoints[3], EBrushSplit split) -{ - // Collect all selected brushes - BrushPtrVector brushes = selection::algorithm::getSelectedBrushes(); - - // Instantiate a scoped walker - BrushByPlaneClipper splitter( - planePoints[0], - planePoints[1], - planePoints[2], - split - ); - - splitter.split(brushes); - - SceneChangeNotify(); -} - void registerCommands() { GlobalCommandSystem().addCommand("CSGSubtract", subtractBrushesFromUnselected); diff --git a/radiant/brush/csg/CSG.h b/radiant/brush/csg/CSG.h index 5ca2a021df..14676c2895 100644 --- a/radiant/brush/csg/CSG.h +++ b/radiant/brush/csg/CSG.h @@ -1,5 +1,4 @@ -#ifndef BRUSH_CSG_H_ -#define BRUSH_CSG_H_ +#pragma once #include "iclipper.h" #include "icommandsystem.h" @@ -45,19 +44,6 @@ void subtractBrushesFromUnselected(const cmd::ArgumentList& args); */ void mergeSelectedBrushes(const cmd::ArgumentList& args); -/** - * greebo: Sets the "clip plane" of the selected brushes in the scene. - */ -void setBrushClipPlane(const Plane3& plane); - -// Classifies the given brush (needed for clipping/csg) -BrushSplitType Brush_classifyPlane(const Brush& brush, const Plane3& plane); - -/** - * greebo: Splits the selected brushes by the given plane. - */ -void splitBrushesByPlane(const Vector3 planePoints[3], EBrushSplit split); - /** * Connect the various events to the functions in this namespace */ @@ -66,4 +52,3 @@ void registerCommands(); } // namespace algorihtm } // namespace brush -#endif /* BRUSH_CSG_H_ */ diff --git a/radiant/brush/csg/BrushByPlaneClipper.cpp b/radiant/clipper/BrushByPlaneClipper.cpp similarity index 90% rename from radiant/brush/csg/BrushByPlaneClipper.cpp rename to radiant/clipper/BrushByPlaneClipper.cpp index b2c3a98c23..f00d3e6209 100644 --- a/radiant/brush/csg/BrushByPlaneClipper.cpp +++ b/radiant/clipper/BrushByPlaneClipper.cpp @@ -1,18 +1,14 @@ #include "BrushByPlaneClipper.h" -#include "CSG.h" #include "scenelib.h" #include "brush/BrushNode.h" #include "ui/texturebrowser/TextureBrowser.h" -namespace brush -{ - namespace algorithm { -BrushByPlaneClipper::BrushByPlaneClipper( - const Vector3& p0, const Vector3& p1, const Vector3& p2, EBrushSplit split) : +BrushByPlaneClipper::BrushByPlaneClipper(const Vector3& p0, const Vector3& p1, + const Vector3& p2, EBrushSplit split) : _p0(p0), _p1(p1), _p2(p2), @@ -30,10 +26,8 @@ void BrushByPlaneClipper::split(const BrushPtrVector& brushes) return; } - for (BrushPtrVector::const_iterator i = brushes.begin(); i != brushes.end(); ++i) + for (const BrushNodePtr& node : brushes) { - const BrushNodePtr& node = *i; - // Don't clip invisible nodes if (!node->visible()) { @@ -52,9 +46,9 @@ void BrushByPlaneClipper::split(const BrushPtrVector& brushes) // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); - BrushSplitType split = Brush_classifyPlane(brush, _split == eFront ? -plane : plane); + BrushSplitType split = brush.classifyPlane(_split == eFront ? -plane : plane); - if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) + if (split.counts[ePlaneBack] > 0 && split.counts[ePlaneFront] > 0) { // the plane intersects this brush if (_split == eFrontAndBack) @@ -171,4 +165,3 @@ void BrushByPlaneClipper::getMostUsedTexturing(const Brush& brush) const } } // namespace algorithm -} // namespace brush diff --git a/radiant/brush/csg/BrushByPlaneClipper.h b/radiant/clipper/BrushByPlaneClipper.h similarity index 96% rename from radiant/brush/csg/BrushByPlaneClipper.h rename to radiant/clipper/BrushByPlaneClipper.h index a0cbb3d709..c372440185 100644 --- a/radiant/brush/csg/BrushByPlaneClipper.h +++ b/radiant/clipper/BrushByPlaneClipper.h @@ -10,7 +10,6 @@ #include "selection/algorithm/Primitives.h" -namespace brush { namespace algorithm { class BrushByPlaneClipper @@ -45,4 +44,3 @@ class BrushByPlaneClipper }; } // namespace algorithm -} // namespace brush diff --git a/radiant/clipper/Clipper.cpp b/radiant/clipper/Clipper.cpp index 511df87046..c8c00a7e83 100644 --- a/radiant/clipper/Clipper.cpp +++ b/radiant/clipper/Clipper.cpp @@ -11,6 +11,7 @@ #include "registry/registry.h" #include "module/StaticModule.h" #include "ClipPoint.h" +#include "SplitAlgorithm.h" #include "brush/csg/CSG.h" #include "debugging/debugging.h" @@ -138,7 +139,7 @@ void Clipper::getPlanePoints(Vector3 planepts[3], const AABB& bounds) const { void Clipper::setClipPlane(const Plane3& plane) { - brush::algorithm::setBrushClipPlane(plane); + algorithm::setBrushClipPlane(plane); } void Clipper::update() { @@ -178,7 +179,7 @@ void Clipper::clip() { AABB bounds(Vector3(0, 0, 0), Vector3(64, 64, 64)); getPlanePoints(planepts, bounds); - brush::algorithm::splitBrushesByPlane(planepts, !_switch ? eFront : eBack); + algorithm::splitBrushesByPlane(planepts, !_switch ? eFront : eBack); reset(); update(); @@ -191,7 +192,7 @@ void Clipper::splitClip() { AABB bounds(Vector3(0, 0, 0), Vector3(64, 64, 64)); getPlanePoints(planepts, bounds); - brush::algorithm::splitBrushesByPlane(planepts, eFrontAndBack); + algorithm::splitBrushesByPlane(planepts, eFrontAndBack); reset(); update(); @@ -246,11 +247,11 @@ const std::string& Clipper::getName() const { const StringSet& Clipper::getDependencies() const { static StringSet _dependencies; - if (_dependencies.empty()) { + if (_dependencies.empty()) + { _dependencies.insert(MODULE_XMLREGISTRY); _dependencies.insert(MODULE_COMMANDSYSTEM); _dependencies.insert(MODULE_PREFERENCESYSTEM); - _dependencies.insert(MODULE_MAINFRAME); } return _dependencies; diff --git a/radiant/clipper/SplitAlgorithm.cpp b/radiant/clipper/SplitAlgorithm.cpp new file mode 100644 index 0000000000..2145887447 --- /dev/null +++ b/radiant/clipper/SplitAlgorithm.cpp @@ -0,0 +1,57 @@ +#include "SplitAlgorithm.h" + +#include "iselection.h" +#include "brush/BrushNode.h" +#include "selection/algorithm/Primitives.h" +#include "BrushByPlaneClipper.h" + +namespace algorithm +{ + +class BrushSetClipPlane : + public SelectionSystem::Visitor +{ + Plane3 _plane; +public: + BrushSetClipPlane(const Plane3& plane) : + _plane(plane) + {} + + virtual ~BrushSetClipPlane() {} + + void visit(const scene::INodePtr& node) const override + { + BrushNodePtr brush = std::dynamic_pointer_cast(node); + + if (brush && node->visible()) + { + brush->setClipPlane(_plane); + } + } +}; + +void setBrushClipPlane(const Plane3& plane) +{ + BrushSetClipPlane walker(plane); + GlobalSelectionSystem().foreachSelected(walker); +} + +void splitBrushesByPlane(const Vector3 planePoints[3], EBrushSplit split) +{ + // Collect all selected brushes + BrushPtrVector brushes = selection::algorithm::getSelectedBrushes(); + + // Instantiate a scoped walker + BrushByPlaneClipper splitter( + planePoints[0], + planePoints[1], + planePoints[2], + split + ); + + splitter.split(brushes); + + SceneChangeNotify(); +} + +} diff --git a/radiant/clipper/SplitAlgorithm.h b/radiant/clipper/SplitAlgorithm.h new file mode 100644 index 0000000000..9cc7a63218 --- /dev/null +++ b/radiant/clipper/SplitAlgorithm.h @@ -0,0 +1,18 @@ +#pragma once + +class Plane3; + +namespace algorithm +{ + +/** + * greebo: Sets the "clip plane" of the selected brushes in the scene. + */ +void setBrushClipPlane(const Plane3& plane); + +/** + * greebo: Splits the selected brushes by the given plane. + */ +void splitBrushesByPlane(const Vector3 planePoints[3], EBrushSplit split); + +} diff --git a/radiant/ui/layers/LayerControl.cpp b/radiant/ui/layers/LayerControl.cpp index 21213c9ede..c1209ef9bf 100644 --- a/radiant/ui/layers/LayerControl.cpp +++ b/radiant/ui/layers/LayerControl.cpp @@ -16,7 +16,6 @@ #include #include -#include "layers/LayerManager.h" #include "LayerControlDialog.h" namespace ui diff --git a/radiant/ui/layers/LayerControlDialog.cpp b/radiant/ui/layers/LayerControlDialog.cpp index 0f25884bc8..ecc8ead193 100644 --- a/radiant/ui/layers/LayerControlDialog.cpp +++ b/radiant/ui/layers/LayerControlDialog.cpp @@ -20,8 +20,7 @@ #include "wxutil/ScrollWindow.h" #include "wxutil/Button.h" -#include "layers/LayerManager.h" -#include "layers/LayerUsageBreakdown.h" +#include "scene/LayerUsageBreakdown.h" namespace ui { diff --git a/tools/msvc/DarkRadiant.vcxproj b/tools/msvc/DarkRadiant.vcxproj index a0144155b9..3eabbadb1a 100644 --- a/tools/msvc/DarkRadiant.vcxproj +++ b/tools/msvc/DarkRadiant.vcxproj @@ -196,6 +196,8 @@ + + @@ -760,7 +762,6 @@ - @@ -908,6 +909,8 @@ + + @@ -1086,7 +1089,6 @@ - diff --git a/tools/msvc/DarkRadiant.vcxproj.filters b/tools/msvc/DarkRadiant.vcxproj.filters index f64a02a053..86830bd5de 100644 --- a/tools/msvc/DarkRadiant.vcxproj.filters +++ b/tools/msvc/DarkRadiant.vcxproj.filters @@ -274,9 +274,6 @@ src\brush\export - - src\brush\csg - src\brush\csg @@ -1153,6 +1150,12 @@ src\ui\layers + + src\clipper + + + src\clipper + @@ -1218,9 +1221,6 @@ src\brush\export - - src\brush\csg - src\brush\csg @@ -2247,6 +2247,12 @@ src\ui\layers + + src\clipper + + + src\clipper +