From 435c41b73bc2761c898a028593992c4598f6ab14 Mon Sep 17 00:00:00 2001 From: Garux Date: Mon, 10 Dec 2018 17:50:40 +0300 Subject: [PATCH] * new vertex editing mode, preserving non modified vertices (=adding/removing faces automatically) with debug prints --- libs/transformlib.h | 4 +- radiant/brush.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++++ radiant/brush.h | 98 ++++++++++++++++++++++++++-- 3 files changed, 246 insertions(+), 9 deletions(-) diff --git a/libs/transformlib.h b/libs/transformlib.h index 629cd792..f6502e47 100644 --- a/libs/transformlib.h +++ b/libs/transformlib.h @@ -83,10 +83,10 @@ struct Skew{ Skew( std::size_t index_, float amount_ ) : index( index_ ), amount( amount_ ){ } bool operator!= ( const Skew& other ) const { - return index != other.index || amount != other.amount; + return !( *this == other ); } bool operator== ( const Skew& other ) const { - return index == other.index && amount == other.amount; + return ( amount == 0 && other.amount == 0 ) || ( index == other.index && amount == other.amount ); } }; diff --git a/radiant/brush.cpp b/radiant/brush.cpp index 2ee67fe4..07591ae7 100644 --- a/radiant/brush.cpp +++ b/radiant/brush.cpp @@ -106,6 +106,9 @@ inline bool Brush_isBounded( const Brush& brush ){ } void Brush::buildBRep(){ + globalOutputStream() << " buildBRep() \n"; + const bool _vertexModeOn = m_vertexModeOn; + bool degenerate = buildWindings(); std::size_t faces_size = 0; @@ -119,6 +122,7 @@ void Brush::buildBRep(){ } if ( degenerate || faces_size < 4 || faceVerticesCount != ( faceVerticesCount >> 1 ) << 1 ) { // sum of vertices for each face of a valid polyhedron is always even + globalOutputStream() << degenerate << " degenerate\n"; m_uniqueVertexPoints.resize( 0 ); vertex_clear(); @@ -305,6 +309,18 @@ void Brush::buildBRep(){ m_faceCentroidPoints[i] = pointvertex_for_windingpoint( m_faces[i]->centroid(), colour_vertex ); } } +globalOutputStream() << _vertexModeOn << " _vertexModeOn\n"; +globalOutputStream() << m_vertexModeOn << " m_vertexModeOn\n"; + // :faceleg: start move end + // m_vertexModeOn 1 1 0 + // _vertexModeOn 0 1 1 + if( _vertexModeOn || m_vertexModeOn ){ + if( !( !m_vertexModeOn && _vertexModeOn && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) ) //don't select in the end of g_bTmpComponentMode + for( const auto& i : m_vertexModeVertices ) + if( i.m_selected ) + for ( Observers::iterator o = m_observers.begin(); o != m_observers.end(); ++o ) + ( *o )->vertex_select( i.m_vertexTransformed ); + } } } @@ -387,3 +403,140 @@ bool brush_filtered( Brush& brush ){ } return false; } + + +class VertexModePlane +{ +public: + Plane3 m_plane; + const Face* m_face; + const Brush::VertexModeVertex* const m_v[3]; + bool m_transformed; + VertexModePlane( const Plane3& plane, const Face* face, + const Brush::VertexModeVertex* v1, const Brush::VertexModeVertex* v2, const Brush::VertexModeVertex* v3, + bool transformed ) : m_plane( plane ), m_face( face ), m_v{ v1, v2, v3 }, m_transformed( transformed ){ + } +}; + +class VertexModePlanes +{ + typedef std::vector Planes; + Planes m_planes; +public: + typedef Planes::const_iterator const_iterator; + typedef Planes::iterator iterator; + void push_back( const VertexModePlane& plane ){ + m_planes.push_back( plane ); + } + iterator find( const Plane3& plane ){ + iterator i = begin(); + for( ; i != end(); ++i ) + if( plane3_equal( plane, i->m_plane ) ) + break; + return i; + } + const_iterator begin() const { + return m_planes.begin(); + } + const_iterator end() const { + return m_planes.end(); + } + iterator begin() { + return m_planes.begin(); + } + iterator end() { + return m_planes.end(); + } + std::size_t size() const { + return m_planes.size(); + } +}; + +const Face* vertex_mode_find_common_face( const Brush::VertexModeVertex& v1, const Brush::VertexModeVertex& v2, const Brush::VertexModeVertex& v3 ){ + const Face* face = 0; + for( const auto& i : v1.m_faces ){ + if( std::find( v2.m_faces.begin(), v2.m_faces.end(), i ) != v2.m_faces.end() + && std::find( v3.m_faces.begin(), v3.m_faces.end(), i ) != v3.m_faces.end() ){ + face = i; + break; + } + } + return face; +} + +#include "quickhull/QuickHull.hpp" +void Brush::vertexModeTransform( const Matrix4& matrix ){ + globalOutputStream() << " vertexModeTransform\n"; + + quickhull::QuickHull quickhull; + std::vector> pointCloud; + pointCloud.reserve( m_vertexModeVertices.size() ); + for( auto& i : m_vertexModeVertices ){ + if( i.m_selected ) + i.m_vertexTransformed = matrix4_transformed_point( matrix, i.m_vertex ); + pointCloud.push_back( quickhull::Vector3( static_cast( i.m_vertexTransformed.x() ), + static_cast( i.m_vertexTransformed.y() ), + static_cast( i.m_vertexTransformed.z() ) ) ); + } + auto hull = quickhull.getConvexHull( pointCloud, false, true, 0.0001 ); + const auto& indexBuffer = hull.getIndexBuffer(); + const size_t triangleCount = indexBuffer.size() / 3; + VertexModePlanes vertexModePlanes; + for( size_t i = 0; i < triangleCount; ++i ) { + const Brush::VertexModeVertex* v[3]; + bool transformed = false; + for( size_t j = 0; j < 3; ++j ){ + v[j] = &m_vertexModeVertices[indexBuffer[i * 3 + j]]; + transformed |= v[j]->m_selected; + } + const Plane3 plane = plane3_for_points( v[0]->m_vertexTransformed, v[1]->m_vertexTransformed, v[2]->m_vertexTransformed ); + if( plane3_valid( plane ) ){ + VertexModePlanes::iterator it = vertexModePlanes.find( plane ); + if( it == vertexModePlanes.end() ){ //not found, add new plane + const Face* face = vertex_mode_find_common_face( *v[0], *v[1], *v[2] ); + if( !face ){ //no common face, use some + face = v[0]->m_faces[0]; + transformed = true; + } + if( vector3_dot( plane.normal(), face->getPlane().plane3().normal() ) < 0 ){ //likely reversed plane + transformed = true; + } + vertexModePlanes.push_back( VertexModePlane( plane, face, v[0], v[2], v[1], transformed ) ); + } + else{ + it->m_transformed |= transformed; + } + } + } + + if( vertexModePlanes.size() >=4 ){ //avoid obvious transform to degenerate + clear(); + for( const auto& i : vertexModePlanes ){ + const Face& face = *i.m_face; + if( i.m_transformed ){ + if( g_brush_textureVertexlock_enabled ){ + Matrix4 local2tex; + Texdef_Construct_local2tex( face.getTexdef().m_projection, face.getShader().width(), face.getShader().height(), face.getPlane().plane3().normal(), local2tex ); + const DoubleVector3 st[3]{ matrix4_transformed_point( local2tex, i.m_v[0]->m_vertex ), + matrix4_transformed_point( local2tex, i.m_v[1]->m_vertex ), + matrix4_transformed_point( local2tex, i.m_v[2]->m_vertex ) }; + const DoubleVector3 points[3]{ i.m_v[0]->m_vertexTransformed, i.m_v[1]->m_vertexTransformed, i.m_v[2]->m_vertexTransformed }; + TextureProjection projection; + Texdef_from_ST( projection, points, st, face.getShader().width(), face.getShader().height() ); + projection.m_brushprimit_texdef.removeScale( face.getShader().width(), face.getShader().height() ); + + addPlane( i.m_v[0]->m_vertexTransformed, i.m_v[1]->m_vertexTransformed, i.m_v[2]->m_vertexTransformed, face.GetShader(), projection ); + + Brush_textureChanged(); + } + else{ + addPlane( i.m_v[0]->m_vertexTransformed, i.m_v[1]->m_vertexTransformed, i.m_v[2]->m_vertexTransformed, face.GetShader(), face.getTexdef().normalised() ); + } + } + else{ + addFace( face ); + } + } + globalOutputStream() << m_faces.size() << " m_faces.size()\n"; + } +} diff --git a/radiant/brush.h b/radiant/brush.h index e4ad315c..ad1d47d6 100644 --- a/radiant/brush.h +++ b/radiant/brush.h @@ -1550,6 +1550,8 @@ virtual void edge_push_back( SelectableEdge& edge ) = 0; virtual void vertex_clear() = 0; virtual void vertex_push_back( SelectableVertex& vertex ) = 0; +virtual void vertex_select( const Vector3& vertex ) = 0; + virtual void DEBUG_verify() const = 0; }; @@ -1800,6 +1802,7 @@ void transformChanged(){ //m_transformChanged = true; planeChanged(); m_transformChanged = true; //experimental fix of cyclic dependency + globalOutputStream() << m_planeChanged << " m_planeChanged\n"; } typedef MemberCaller TransformChangedCaller; @@ -1858,18 +1861,51 @@ void snapto( float snap ){ } } void revertTransform(){ + globalOutputStream() << " revertTransform\n"; for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { ( *i )->revertTransform(); } } void freezeTransform(){ + globalOutputStream() << " freezeTransform\n"; for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { ( *i )->freezeTransform(); } } + class VertexModeVertex + { + public: + const Vector3 m_vertex; + Vector3 m_vertexTransformed; + const bool m_selected; + std::vector m_faces; + VertexModeVertex( const Vector3& vertex, const bool selected ) : m_vertex( vertex ), m_vertexTransformed( vertex ), m_selected( selected ) { + } + }; + typedef std::vector VertexModeVertices; + + +VertexModeVertices m_vertexModeVertices; +bool m_vertexModeOn{false}; + +void vertexModeInit(){ + globalOutputStream() << " vertexModeInit(){\n"; + m_vertexModeOn = true; + m_vertexModeVertices.clear(); + undoSave(); +} + +void vertexModeFree(){ + globalOutputStream() << " vertexModeFree(){\n"; + m_vertexModeOn = false; +// m_vertexModeVertices.clear(); //keep, as it is required by buildBRep() after this call +} + +void vertexModeTransform( const Matrix4& matrix ); + /// \brief Returns the absolute index of the \p faceVertex. std::size_t absoluteIndex( FaceVertexId faceVertex ){ std::size_t index = 0; @@ -2374,6 +2410,9 @@ bool buildWindings(){ { m_aabb_local = AABB(); + if( m_faces.size() ) + m_faces[0]->plane3(); //force evaluateTransform() first, as m_faces is changed during vertexModeTransform + for ( std::size_t i = 0; i < m_faces.size(); ++i ) { Face& f = *m_faces[i]; @@ -3145,6 +3184,21 @@ void selectVerticesOnFaces( const FaceInstances_ptrs& faceinstances ){ } while ( faceVertex.getFace() != m_vertex->m_faceVertex.getFace() ); } +void gather( Brush::VertexModeVertices& vertexModeVertices ) const { + vertexModeVertices.push_back( Brush::VertexModeVertex( m_vertex->getFace().getWinding()[m_vertex->m_faceVertex.getVertex()].vertex, isSelected() ) ); + FaceVertexId faceVertex = m_vertex->m_faceVertex; + do + { + vertexModeVertices.back().m_faces.push_back( &m_faceInstances[faceVertex.getFace()].getFace() ); + faceVertex = next_vertex( m_vertex->m_faces, faceVertex ); + } + while ( faceVertex.getFace() != m_vertex->m_faceVertex.getFace() ); +} +void vertex_select( const Vector3& vertex ){ + if( vector3_length_squared( vertex - m_vertex->getFace().getWinding()[m_vertex->m_faceVertex.getVertex()].vertex ) < ( 0.1 * 0.1 ) ){ + setSelected( true ); + } +} }; class BrushInstanceVisitor @@ -3341,6 +3395,16 @@ void vertex_push_back( SelectableVertex& vertex ){ m_vertexInstances.push_back( VertexInstance( m_faceInstances, vertex ) ); } +void vertex_select( const Vector3& vertex ){ + for( auto& i : m_vertexInstances ) + i.vertex_select( vertex ); + for ( const auto& i : m_faceInstances ) + if( i.selectedComponents( SelectionSystem::eVertex ) ) //got something selected, okay + return; + if( !m_vertexInstances.empty() ) + m_vertexInstances[0].setSelected( true ); //select at least something to prevent transform interruption after removing all selected vertices during vertexModeTransform +} + void DEBUG_verify() const { ASSERT_MESSAGE( m_faceInstances.size() == m_brush.DEBUG_size(), "FATAL: mismatch" ); } @@ -3715,10 +3779,25 @@ void snapComponents( float snap ){ } } void evaluateTransform(){ - if( m_transform.m_transformFrozen && !m_transform.isIdentity() ){ + globalOutputStream() << " evaluateTransform\n"; + if( m_transform.m_transformFrozen ) + m_brush.vertexModeFree(); + if( m_transform.m_transformFrozen && !m_transform.isIdentity() ){ /* new transform */ m_transform.m_transformFrozen = false; for( auto& i : m_faceInstances ) i.getFace().cacheCentroid(); + + if( m_transform.getType() == TRANSFORM_COMPONENT ){ + for ( const auto& i : m_faceInstances ){ + if( i.selectedComponents( SelectionSystem::eVertex ) ){ + m_brush.vertexModeInit(); + for ( const auto& i : m_vertexInstances ){ + i.gather( m_brush.m_vertexModeVertices ); + } + break; + } + } + } } const Matrix4 matrix( m_transform.calculateTransform() ); @@ -3728,12 +3807,17 @@ void evaluateTransform(){ } else { - const bool tmp = g_brush_texturelock_enabled; - /* do not want texture projection transformation while resizing brush */ - if( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eDrag && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) - g_brush_texturelock_enabled = false; - transformComponents( matrix ); - g_brush_texturelock_enabled = tmp; + if( m_brush.m_vertexModeOn ){ + m_brush.vertexModeTransform( matrix ); + } + else{ + const bool tmp = g_brush_texturelock_enabled; + /* do not want texture projection transformation while resizing brush */ + if( GlobalSelectionSystem().ManipulatorMode() == SelectionSystem::eDrag && GlobalSelectionSystem().Mode() == SelectionSystem::ePrimitive ) + g_brush_texturelock_enabled = false; + transformComponents( matrix ); + g_brush_texturelock_enabled = tmp; + } } } void applyTransform(){