/* Copyright 2004, 2005 Nicholas Bishop * * This file is part of SharpConstruct. * * SharpConstruct 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. * * SharpConstruct 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 SharpConstruct; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "Brush.h" #include "Mesh.h" #include #include #include using namespace SharpConstruct; using SharpConstruct::Optimized::Point3D; using SharpConstruct::Optimized::Normal3D; EditData Mesh::GetMirror( bool x, bool y, bool z ) const { EditData e; e.SIndex = x * 4 + y * 2 + z; e.Center = _current_selection; e.Up = _view_up_normal; e.Left = _view_right_normal; e.Z = _view_z_normal; if( x ) { e.Center.X() = -e.Center.X(); e.Up.X() = -e.Up.X(); e.Left.X() = -e.Left.X(); e.Z.X() = -e.Z.X(); } if( y ) { e.Center.Y() = -e.Center.Y(); e.Up.Y() = -e.Up.Y(); e.Left.Y() = -e.Left.Y(); e.Z.Y() = -e.Z.Y(); } if( z ) { e.Center.Z() = -e.Center.Z(); e.Up.Z() = -e.Up.Z(); e.Left.Z() = -e.Left.Z(); e.Z.Z() = -e.Z.Z(); } return e; } Math::PolarPoint Mesh::Relative2DLocation( const EditData& e, Point3D x, float len ) const { const float PI = 3.1415; Point3D t2( x - e.Center ); Normalize( t2 ); float theta = ( e.Left * t2 ).HorizAdd(); // Avoid NaN errors if( theta < -1 ) theta = -1; else if( theta > 1 ) theta = 1; theta = acos( theta ); /* Checks whether theta should be in the III/IV quadrants using the dot product with the Up vector */ if( ( e.Up * t2 ).HorizAdd() > 0 ) theta = 2 * PI - theta; return Math::PolarPoint( len / _selection_radius, theta ); } unsigned FindInitPoint( const VisibleElementData& _visible_elements, Optimized::Point3DVector& _vertex_locations, EditData& e, const float _selection_radius ) __attribute__ ((noinline)); // I seperated this out for better profiling data, it should be made member of Mesh unsigned FindInitPoint( const VisibleElementData& _visible_elements, Optimized::Point3DVector& _vertex_locations, EditData& e, const float _selection_radius ) { unsigned area_index( 0 ); float tmp_distance; if( _selection_radius == 0 ) return 0; //std::cout << _selection_radius << std::endl; // The point of this loop is just to get one vertex that is within the Radius unsigned i; for( i = 0; i < _visible_elements.Vertices; i++ ) { e.Center.FastDistance( _vertex_locations[ i ], tmp_distance ); if( tmp_distance < _selection_radius ) { area_index = i; break; } } return area_index; } void Mesh::FindActiveVertices( std::vector< ActiveData >& active_data, EditData& e ) { active_data.clear(); unsigned area_index = 0; if( _selected_vertex[ e.SIndex ] >= _vertex_locations.size() ) _selected_vertex[ e.SIndex ] = 0; // If a point used last time through the loop is within the Radius, use it! if( _vertex_locations[ _selected_vertex[ e.SIndex ] ].Distance( e.Center ) < _selection_radius ) { area_index = _selected_vertex[ e.SIndex ]; } else { area_index = FindInitPoint( _visible_elements, _vertex_locations, e, _selection_radius ); } // Using a vector seems to be at least slightly faster than a set std::vector< char > checked( _vertex_locations.size(), false ); std::queue< unsigned > untested; // Load in the point we already know is inside... untested.push( area_index ); while( !untested.empty() ) { const unsigned current( untested.front() ); untested.pop(); if( checked[ current ] ) continue; checked[ current ] = true; const float distance( e.Center.Distance( _vertex_locations[ current ] ) ); if( distance < _selection_radius ) { const float strength( CurrentBrush().AlphaStrength( Relative2DLocation( e, VertexLocations()[ current ], distance ) ) ); active_data.push_back( ActiveData( current, strength ) ); } else continue; // Loop through each triangle using the current point for( unsigned i = 0; i < _vertex_users[ current ].Triangles.size(); ++i ) { // Set the current polygon const unsigned polygon_index( _vertex_users[ current ].Triangles[ i ] ); if( polygon_index < _visible_elements.Triangles ) { // Loop through each vertex in the polygon for( unsigned j = 0; j <= 2; ++j ) { // If the current active point equals the current VertexIndex... if( _triangles[ polygon_index ].V[ j ] == current ) { const unsigned add( j + 1 ); const unsigned next_point_index( _triangles[ polygon_index ].V[ add > 2 ? 0 : add ] ); if( next_point_index < _visible_elements.Vertices ) untested.push( next_point_index ); break; } } } } // Loop through each quad using the current point for( unsigned i = 0; i < _vertex_users[ current ].Quads.size(); ++i ) { // Set the current polygon const unsigned polygon_index( _vertex_users[ current ].Quads[ i ] ); if( polygon_index < _visible_elements.Quads ) { // Loop through each vertex in the polygon for( unsigned j = 0; j <= 3; ++j ) { // If the current active point equals the current VertexIndex... if( _quads[ polygon_index ].V[ j ] == current ) { const unsigned add( j + 1 ); const unsigned next_point_index( _quads[ polygon_index ].V[ add > 3 ? 0 : add ] ); if( next_point_index < _visible_elements.Vertices ) untested.push( next_point_index ); break; } } } } } ///// if( active_data.size() > 0 ) _selected_vertex[ e.SIndex ] = active_data[ 0 ].Index(); for( std::vector< ActiveData >::iterator i = active_data.begin(); i != active_data.end(); ++i ) _modified_vertex_indices.push_back( i->Index() ); //std::cout << active_data.size() << std::endl; } void Mesh::AdaptiveSubdivide() { #if 0 using Optimized::Point3D; // Subdivide active quads typedef std::list< unsigned >::iterator iterator; for( iterator i = _damaged_quads.begin(); i != _damaged_quads.end(); ++i ) { const unsigned poly( *i ); // Generate new center const unsigned center( VertexLocations().size() ); VertexLocations().push_back( ( VertexLocations()[ Quads()[ poly ].V[ 0 ] ] + VertexLocations()[ Quads()[ poly ].V[ 1 ] ] + VertexLocations()[ Quads()[ poly ].V[ 2 ] ] + VertexLocations()[ Quads()[ poly ].V[ 3 ] ] ) / 4 ); // Generate new edge vertices unsigned everts[ 4 ]; for( unsigned j = 0; j <= 3; ++j ) { const unsigned k( j < 3 ? j + 1 : 0 ); everts[ j ] = VertexLocations().size(); VertexLocations().resize( everts[ j ] + 1 ); VertexLocations()[ everts[ j ] ].Midpoint( VertexLocations()[ Quads()[ poly ].V[ j ] ], VertexLocations()[ Quads()[ poly ].V[ k ] ] ); } // Create three new polys for( unsigned j = 1; j <= 3; ++j ) { const unsigned k( j - 1 ); Quads().push_back( Quad( Quads()[ poly ].V[ j ], everts[ j ], center, everts[ k ] ) ); } // Use the first poly's loc for the last new one const Quad copy( Quads()[ poly ] ); Quads()[ poly ] = Quad( copy.V[ 0 ], everts[ 0 ], center, everts[ 3 ] ); //Quads()[ poly ] = Quad( everts[ 3 ], center, everts[ 0 ], copy.V[ 0 ] ); //Quads()[ poly ].V[ 1 ] = everts[ 0 ]; //Quads()[ poly ] = Quad( 0, 0, 0, 0 ); } // Match array sizes VertexNormals().resize( VertexLocations().size() ); VertexColors().resize( VertexLocations().size() ); _quad_normals.resize( Quads().size() ); _recalculate_vertex_users(); _change_operation( true, true ); _reset_visibles(); RecalculateAllNormals(); #endif }