/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "brush.h" #include "signal/signal.h" Signal0 g_brushTextureChangedCallbacks; void Brush_addTextureChangedCallback( const SignalHandler& handler ){ g_brushTextureChangedCallbacks.connectLast( handler ); } void Brush_textureChanged(){ g_brushTextureChangedCallbacks(); } QuantiseFunc Face::m_quantise; EBrushType Face::m_type; EBrushType FacePlane::m_type; bool g_brush_texturelock_enabled = true; EBrushType Brush::m_type; double Brush::m_maxWorldCoord = 0; Shader* Brush::m_state_point; Shader* BrushClipPlane::m_state = 0; Shader* BrushInstance::m_state_selpoint; Counter* BrushInstance::m_counter = 0; FaceInstanceSet g_SelectedFaceInstances; struct SListNode { SListNode* m_next; }; class ProximalVertex { public: const SListNode* m_vertices; ProximalVertex( const SListNode* next ) : m_vertices( next ){ } bool operator<( const ProximalVertex& other ) const { if ( !( operator==( other ) ) ) { return m_vertices < other.m_vertices; } return false; } bool operator==( const ProximalVertex& other ) const { const SListNode* v = m_vertices; std::size_t DEBUG_LOOP = 0; do { if ( v == other.m_vertices ) { return true; } v = v->m_next; //ASSERT_MESSAGE(DEBUG_LOOP < c_brush_maxFaces, "infinite loop"); if ( !( DEBUG_LOOP < c_brush_maxFaces ) ) { break; } ++DEBUG_LOOP; } while ( v != m_vertices ); return false; } }; typedef Array ProximalVertexArray; std::size_t ProximalVertexArray_index( const ProximalVertexArray& array, const ProximalVertex& vertex ){ return vertex.m_vertices - array.data(); } inline bool Brush_isBounded( const Brush& brush ){ for ( Brush::const_iterator i = brush.begin(); i != brush.end(); ++i ) { if ( !( *i )->is_bounded() ) { return false; } } return true; } void Brush::buildBRep(){ bool degenerate = buildWindings(); std::size_t faces_size = 0; std::size_t faceVerticesCount = 0; for ( Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { if ( ( *i )->contributes() ) { ++faces_size; } faceVerticesCount += ( *i )->getWinding().numpoints; } if ( degenerate || faces_size < 4 || faceVerticesCount != ( faceVerticesCount >> 1 ) << 1 ) { // sum of vertices for each face of a valid polyhedron is always even m_uniqueVertexPoints.resize( 0 ); vertex_clear(); edge_clear(); m_edge_indices.resize( 0 ); m_edge_faces.resize( 0 ); m_faceCentroidPoints.resize( 0 ); m_uniqueEdgePoints.resize( 0 ); m_uniqueVertexPoints.resize( 0 ); for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { ( *i )->getWinding().resize( 0 ); } } else { { typedef std::vector FaceVertices; FaceVertices faceVertices; faceVertices.reserve( faceVerticesCount ); { for ( std::size_t i = 0; i != m_faces.size(); ++i ) { for ( std::size_t j = 0; j < m_faces[i]->getWinding().numpoints; ++j ) { faceVertices.push_back( FaceVertexId( i, j ) ); } } } IndexBuffer uniqueEdgeIndices; typedef VertexBuffer UniqueEdges; UniqueEdges uniqueEdges; uniqueEdgeIndices.reserve( faceVertices.size() ); uniqueEdges.reserve( faceVertices.size() ); { ProximalVertexArray edgePairs; edgePairs.resize( faceVertices.size() ); { for ( std::size_t i = 0; i < faceVertices.size(); ++i ) { edgePairs[i].m_next = edgePairs.data() + absoluteIndex( next_edge( m_faces, faceVertices[i] ) ); } } { UniqueVertexBuffer inserter( uniqueEdges ); for ( ProximalVertexArray::iterator i = edgePairs.begin(); i != edgePairs.end(); ++i ) { uniqueEdgeIndices.insert( inserter.insert( ProximalVertex( &( *i ) ) ) ); } } { edge_clear(); m_select_edges.reserve( uniqueEdges.size() ); for ( UniqueEdges::iterator i = uniqueEdges.begin(); i != uniqueEdges.end(); ++i ) { edge_push_back( faceVertices[ProximalVertexArray_index( edgePairs, *i )] ); } } { m_edge_faces.resize( uniqueEdges.size() ); for ( std::size_t i = 0; i < uniqueEdges.size(); ++i ) { FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( edgePairs, uniqueEdges[i] )]; m_edge_faces[i] = EdgeFaces( faceVertex.getFace(), m_faces[faceVertex.getFace()]->getWinding()[faceVertex.getVertex()].adjacent ); } } { m_uniqueEdgePoints.resize( uniqueEdges.size() ); for ( std::size_t i = 0; i < uniqueEdges.size(); ++i ) { FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( edgePairs, uniqueEdges[i] )]; const Winding& w = m_faces[faceVertex.getFace()]->getWinding(); Vector3 edge = vector3_mid( w[faceVertex.getVertex()].vertex, w[Winding_next( w, faceVertex.getVertex() )].vertex ); m_uniqueEdgePoints[i] = pointvertex_for_windingpoint( edge, colour_vertex ); } } } IndexBuffer uniqueVertexIndices; typedef VertexBuffer UniqueVertices; UniqueVertices uniqueVertices; uniqueVertexIndices.reserve( faceVertices.size() ); uniqueVertices.reserve( faceVertices.size() ); { ProximalVertexArray vertexRings; vertexRings.resize( faceVertices.size() ); { for ( std::size_t i = 0; i < faceVertices.size(); ++i ) { vertexRings[i].m_next = vertexRings.data() + absoluteIndex( next_vertex( m_faces, faceVertices[i] ) ); } } { UniqueVertexBuffer inserter( uniqueVertices ); for ( ProximalVertexArray::iterator i = vertexRings.begin(); i != vertexRings.end(); ++i ) { uniqueVertexIndices.insert( inserter.insert( ProximalVertex( &( *i ) ) ) ); } } { vertex_clear(); m_select_vertices.reserve( uniqueVertices.size() ); for ( UniqueVertices::iterator i = uniqueVertices.begin(); i != uniqueVertices.end(); ++i ) { vertex_push_back( faceVertices[ProximalVertexArray_index( vertexRings, ( *i ) )] ); } } { m_uniqueVertexPoints.resize( uniqueVertices.size() ); for ( std::size_t i = 0; i < uniqueVertices.size(); ++i ) { FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( vertexRings, uniqueVertices[i] )]; const Winding& winding = m_faces[faceVertex.getFace()]->getWinding(); m_uniqueVertexPoints[i] = pointvertex_for_windingpoint( winding[faceVertex.getVertex()].vertex, colour_vertex ); } } } if ( ( uniqueVertices.size() + faces_size ) - uniqueEdges.size() != 2 ) { globalErrorStream() << "Final B-Rep: inconsistent vertex count\n"; } #if BRUSH_CONNECTIVITY_DEBUG if ( ( uniqueVertices.size() + faces_size ) - uniqueEdges.size() != 2 ) { for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { std::size_t faceIndex = std::distance( m_faces.begin(), i ); if ( !( *i )->contributes() ) { globalOutputStream() << "face: " << Unsigned( faceIndex ) << " does not contribute\n"; } Winding_printConnectivity( ( *i )->getWinding() ); } } #endif // edge-index list for wireframe rendering { m_edge_indices.resize( uniqueEdgeIndices.size() ); for ( std::size_t i = 0, count = 0; i < m_faces.size(); ++i ) { const Winding& winding = m_faces[i]->getWinding(); for ( std::size_t j = 0; j < winding.numpoints; ++j ) { const RenderIndex edge_index = uniqueEdgeIndices[count + j]; m_edge_indices[edge_index].first = uniqueVertexIndices[count + j]; m_edge_indices[edge_index].second = uniqueVertexIndices[count + Winding_next( winding, j )]; } count += winding.numpoints; } } } { m_faceCentroidPoints.resize( m_faces.size() ); for ( std::size_t i = 0; i < m_faces.size(); ++i ) { m_faces[i]->construct_centroid(); m_faceCentroidPoints[i] = pointvertex_for_windingpoint( m_faces[i]->centroid(), colour_vertex ); } } } } class FaceFilterWrapper : public Filter { FaceFilter& m_filter; bool m_active; bool m_invert; public: FaceFilterWrapper( FaceFilter& filter, bool invert ) : m_filter( filter ), m_invert( invert ){ } void setActive( bool active ){ m_active = active; } bool active(){ return m_active; } bool filter( const Face& face ){ return m_invert ^ m_filter.filter( face ); } }; typedef std::list FaceFilters; FaceFilters g_faceFilters; void add_face_filter( FaceFilter& filter, int mask, bool invert ){ g_faceFilters.push_back( FaceFilterWrapper( filter, invert ) ); GlobalFilterSystem().addFilter( g_faceFilters.back(), mask ); } bool face_filtered( Face& face ){ for ( FaceFilters::iterator i = g_faceFilters.begin(); i != g_faceFilters.end(); ++i ) { if ( ( *i ).active() && ( *i ).filter( face ) ) { return true; } } return false; } class BrushFilterWrapper : public Filter { bool m_active; bool m_invert; BrushFilter& m_filter; public: BrushFilterWrapper( BrushFilter& filter, bool invert ) : m_invert( invert ), m_filter( filter ){ } void setActive( bool active ){ m_active = active; } bool active(){ return m_active; } bool filter( const Brush& brush ){ return m_invert ^ m_filter.filter( brush ); } }; typedef std::list BrushFilters; BrushFilters g_brushFilters; void add_brush_filter( BrushFilter& filter, int mask, bool invert ){ g_brushFilters.push_back( BrushFilterWrapper( filter, invert ) ); GlobalFilterSystem().addFilter( g_brushFilters.back(), mask ); } bool brush_filtered( Brush& brush ){ for ( BrushFilters::iterator i = g_brushFilters.begin(); i != g_brushFilters.end(); ++i ) { if ( ( *i ).active() && ( *i ).filter( brush ) ) { return true; } } return false; }