From 6e88e7b746807d6d8c7bbb22b3fc7decbf7e20a9 Mon Sep 17 00:00:00 2001 From: Garux Date: Sun, 8 Mar 2020 17:23:02 +0300 Subject: [PATCH] * DragExtrudeFaces: diagonal extruded brushes joints if extruding multiple faces per brush --- radiant/csg.cpp | 2 +- radiant/selection.cpp | 196 +++++++++++++++++++++++++++++++++++------- 2 files changed, 167 insertions(+), 31 deletions(-) diff --git a/radiant/csg.cpp b/radiant/csg.cpp index 8b4b24bd..90a90bc9 100644 --- a/radiant/csg.cpp +++ b/radiant/csg.cpp @@ -216,7 +216,7 @@ public: } } }; -/* brush0, brush2 are supposed to have same amount of faces in the same order */ +/* brush0, brush2 are supposed to have same amount of faces in the same order; brush2 bigger than brush0 */ void brush_extrudeDiag( const Brush& brush0, const Brush& brush2, brush_vector_t& m_out, const HollowSettings& m_settings ){ TextureProjection projection; TexDef_Construct_Default( projection ); diff --git a/radiant/selection.cpp b/radiant/selection.cpp index 9a50f12e..a5f2ee0f 100644 --- a/radiant/selection.cpp +++ b/radiant/selection.cpp @@ -811,6 +811,15 @@ public: BrushInstance* m_brushInstance; struct InFaceOutBrush{ Face* m_face; PlanePoints m_planepoints; Brush* m_outBrush; }; std::vector m_faces; + std::vector::iterator faceFind( const Face* face ){ + return std::find_if( m_faces.begin(), m_faces.end(), [face]( const InFaceOutBrush& infaceoutbrush ){ return face == infaceoutbrush.m_face; } ); + } + std::vector::const_iterator faceFind( const Face* face ) const { + return std::find_if( m_faces.begin(), m_faces.end(), [face]( const InFaceOutBrush& infaceoutbrush ){ return face == infaceoutbrush.m_face; } ); + } + bool faceExcluded( const Face* face ) const { + return faceFind( face ) == m_faces.end(); + } }; std::vector m_extrudeSources; @@ -891,24 +900,33 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const } } for( ExtrudeSource& source : m_extrudeSources ){ - for( auto& infaceoutbrush : source.m_faces ){ - const Face* face = infaceoutbrush.m_face; - Brush* brush = infaceoutbrush.m_outBrush; - brush->clear(); + Brush& brush0 = source.m_brushInstance->getBrush(); + if( source.m_faces.size() > 1 ){ + Brush* tmpbrush = new Brush( brush0 ); + offsetFaces( source, *tmpbrush, offset ); + brush_extrudeDiag( brush0, *tmpbrush, source ); + delete tmpbrush; + } + else{ + for( auto& infaceoutbrush : source.m_faces ){ + const Face* face = infaceoutbrush.m_face; + Brush* brush = infaceoutbrush.m_outBrush; + brush->clear(); - Face* f = brush->addFace( *face ); - f->getPlane().offset( offset ); - f->planeChanged(); + Face* f = brush->addFace( *face ); + f->getPlane().offset( offset ); + f->planeChanged(); - f = brush->addFace( *face ); - f->getPlane().reverse(); - f->planeChanged(); + f = brush->addFace( *face ); + f->getPlane().reverse(); + f->planeChanged(); - for( const WindingVertex& vertex : face->getWinding() ){ - if( vertex.adjacent != c_brush_maxFaces ){ - Brush::const_iterator faceIt = source.m_brushInstance->getBrush().begin(); - std::advance( faceIt, vertex.adjacent ); - f = brush->addFace( **faceIt ); + for( const WindingVertex& vertex : face->getWinding() ){ + if( vertex.adjacent != c_brush_maxFaces ){ + Brush::const_iterator faceIt = brush0.begin(); + std::advance( faceIt, vertex.adjacent ); + brush->addFace( **faceIt ); + } } } } @@ -931,24 +949,32 @@ void Transform( const Matrix4& manip2object, const Matrix4& device2manip, const face->getPlane().copy( infaceoutbrush.m_planepoints ); face->planeChanged(); } - for( auto& infaceoutbrush : source.m_faces ){ - Face* face = infaceoutbrush.m_face; - Brush* brush = infaceoutbrush.m_outBrush; - brush->clear(); + if( source.m_faces.size() > 1 ){ + Brush* tmpbrush = new Brush( brush0 ); + tmpbrush->evaluateBRep(); + offsetFaces( source, brush0, offset ); + if( brush0.hasContributingFaces() ) + brush_extrudeDiag( brush0, *tmpbrush, source ); + delete tmpbrush; + } + else{ + for( auto& infaceoutbrush : source.m_faces ){ + Face* face = infaceoutbrush.m_face; + Brush* brush = infaceoutbrush.m_outBrush; + brush->clear(); - brush->copy( brush0 ); + brush->copy( brush0 ); - Face* f = brush->addFace( *face ); - face->assign_planepts( infaceoutbrush.m_planepoints ); - f->getPlane().offset( offset ); - f->getPlane().reverse(); - f->planeChanged(); + Face* f = brush->addFace( *face ); + f->getPlane().offset( offset ); + f->getPlane().reverse(); + f->planeChanged(); - brush->removeEmptyFaces(); - // modify original brush - face->getPlane().copy( infaceoutbrush.m_planepoints ); - face->getPlane().offset( offset ); - face->planeChanged(); + brush->removeEmptyFaces(); + // modify original brush + face->getPlane().offset( offset ); + face->planeChanged(); + } } } } @@ -957,6 +983,116 @@ void set0( const Vector3& start, const Plane3& planeSelected ){ m_0 = start; m_planeSelected = planeSelected; } + +private: +void offsetFaces( const ExtrudeSource& source, Brush& brush, const float offset ){ + const Brush& brush0 = source.m_brushInstance->getBrush(); + for( Brush::const_iterator i0 = brush0.begin(); i0 != brush0.end(); ++i0 ){ + const Face& face0 = *( *i0 ); + if( !source.faceExcluded( &face0 ) ){ + Brush::const_iterator i = brush.begin(); + std::advance( i, std::distance( brush0.begin(), i0 ) ); + Face& face = *( *i ); + face.getPlane().offset( offset ); + face.planeChanged(); + } + } + brush.evaluateBRep(); +} +/* brush0, brush2 are supposed to have same amount of faces in the same order; brush2 bigger than brush0 */ +void brush_extrudeDiag( const Brush& brush0, const Brush& brush2, ExtrudeSource& source ){ + TextureProjection projection; + TexDef_Construct_Default( projection ); + + for( Brush::const_iterator i0 = brush0.begin(); i0 != brush0.end(); ++i0 ){ + const Face& face0 = *( *i0 ); + Brush::const_iterator i2 = brush2.begin(); + std::advance( i2, std::distance( brush0.begin(), i0 ) ); + const Face& face2 = *( *i2 ); + + auto infaceoutbrush_iter = source.faceFind( &face0 ); // brush0 = source.m_brushInstance->getBrush() + if( infaceoutbrush_iter != source.m_faces.end() ) { + if( face0.contributes() || face2.contributes() ) { + const char* shader = face0.GetShader(); + + Brush* outBrush = ( *infaceoutbrush_iter ).m_outBrush; + outBrush->clear(); + + if( face0.contributes() ){ + if( Face* newFace = outBrush->addFace( face0 ) ) { + newFace->flipWinding(); + } + } + if( face2.contributes() ){ + outBrush->addFace( face2 ); + } + + if( face0.contributes() && face2.contributes() ){ //sew two valid windings + const auto addSidePlanes = [&outBrush, shader, &projection]( const Winding& winding0, const Winding& winding2, const DoubleVector3 normal, const bool swap ){ + for( std::size_t index0 = 0; index0 < winding0.numpoints; ++index0 ){ + const std::size_t next = Winding_next( winding0, index0 ); + Vector3 BestPoint; + double bestdot = -1; + for( std::size_t index2 = 0; index2 < winding2.numpoints; ++index2 ){ + const double dot = vector3_dot( + vector3_normalised( + vector3_cross( + winding0[index0].vertex - winding0[next].vertex, + winding0[index0].vertex - winding2[index2].vertex + ) + ), + normal + ); + if( dot > bestdot ) { + bestdot = dot; + BestPoint = winding2[index2].vertex; + } + } + outBrush->addPlane( winding0[swap? next : index0].vertex, + winding0[swap? index0 : next].vertex, + BestPoint, + shader, + projection ); + } + }; + //insert side planes from each winding perspective, as their form may change after brush expansion + addSidePlanes( face0.getWinding(), face2.getWinding(), face0.getPlane().plane3().normal(), false ); + addSidePlanes( face2.getWinding(), face0.getWinding(), face0.getPlane().plane3().normal(), true ); + } + else{ //one valid winding: this way may produce garbage with complex brushes, extruded partially, but does preferred result with simple ones + const auto addSidePlanes = [&outBrush, shader, &projection]( const Winding& winding0, const Brush& brush2, const Plane3 plane, const bool swap ){ + for( std::size_t index0 = 0; index0 < winding0.numpoints; ++index0 ){ + const std::size_t next = Winding_next( winding0, index0 ); + Vector3 BestPoint; + double bestdist = 999999; + for( const Face* f : brush2 ) { + const Winding& winding2 = f->getWinding(); + for( std::size_t index2 = 0; index2 < winding2.numpoints; ++index2 ){ + const double testdist = vector3_length( winding0[index0].vertex - winding2[index2].vertex ); + if( testdist < bestdist && plane3_distance_to_point( plane, winding2[index2].vertex ) > .05 ) { + bestdist = testdist; + BestPoint = winding2[index2].vertex; + } + } + } + outBrush->addPlane( winding0[swap? next : index0].vertex, + winding0[swap? index0 : next].vertex, + BestPoint, + shader, + projection ); + } + }; + + if( face0.contributes() ) + addSidePlanes( face0.getWinding(), brush2, face0.getPlane().plane3(), false ); + else if( face2.contributes() ) + addSidePlanes( face2.getWinding(), brush0, plane3_flipped( face2.getPlane().plane3() ), true ); + } + outBrush->removeEmptyFaces(); + } + } + } +} };