Equalizer
1.4.1
|
00001 00002 /* Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch> 00003 * 2009-2012, Stefan Eilemann <eile@equalizergraphics.com> 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * - Redistributions of source code must retain the above copyright notice, this 00009 * list of conditions and the following disclaimer. 00010 * - Redistributions in binary form must reproduce the above copyright notice, 00011 * this list of conditions and the following disclaimer in the documentation 00012 * and/or other materials provided with the distribution. 00013 * - Neither the name of Eyescale Software GmbH nor the names of its 00014 * contributors may be used to endorse or promote products derived from this 00015 * software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 #include "vertexData.h" 00031 #include "ply.h" 00032 00033 #include <cstdlib> 00034 #include <algorithm> 00035 00036 #if (( __GNUC__ > 4 ) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) ) 00037 # include <parallel/algorithm> 00038 using __gnu_parallel::sort; 00039 #else 00040 using std::sort; 00041 #endif 00042 00043 using namespace mesh; 00044 00045 /* Contructor. */ 00046 VertexData::VertexData() 00047 : _invertFaces( false ) 00048 { 00049 _boundingBox[0] = Vertex( 0.0f ); 00050 _boundingBox[1] = Vertex( 0.0f ); 00051 } 00052 00053 00054 /* Read the vertex and (if available/wanted) color data from the open file. */ 00055 void VertexData::readVertices( PlyFile* file, const int nVertices, 00056 const bool readColors ) 00057 { 00058 // temporary vertex structure for ply loading 00059 struct _Vertex 00060 { 00061 float x; 00062 float y; 00063 float z; 00064 unsigned char r; 00065 unsigned char g; 00066 unsigned char b; 00067 } vertex; 00068 00069 PlyProperty vertexProps[] = 00070 { 00071 { "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 }, 00072 { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 }, 00073 { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 }, 00074 { "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, r ), 0, 0, 0, 0 }, 00075 { "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, g ), 0, 0, 0, 0 }, 00076 { "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, b ), 0, 0, 0, 0 } 00077 }; 00078 00079 // use all 6 properties when reading colors, only the first 3 otherwise 00080 int limit = readColors ? 6 : 3; 00081 for( int i = 0; i < limit; ++i ) 00082 ply_get_property( file, "vertex", &vertexProps[i] ); 00083 00084 vertices.clear(); 00085 vertices.reserve( nVertices ); 00086 00087 if( readColors ) 00088 { 00089 colors.clear(); 00090 colors.reserve( nVertices ); 00091 } 00092 00093 // read in the vertices 00094 for( int i = 0; i < nVertices; ++i ) 00095 { 00096 ply_get_element( file, static_cast< void* >( &vertex ) ); 00097 vertices.push_back( Vertex( vertex.x, vertex.y, vertex.z ) ); 00098 if( readColors ) 00099 colors.push_back( Color( vertex.r, vertex.g, vertex.b, 0 ) ); 00100 } 00101 } 00102 00103 00104 /* Read the index data from the open file. */ 00105 void VertexData::readTriangles( PlyFile* file, const int nFaces ) 00106 { 00107 // temporary face structure for ply loading 00108 struct _Face 00109 { 00110 unsigned char nVertices; 00111 int* vertices; 00112 } face; 00113 00114 PlyProperty faceProps[] = 00115 { 00116 { "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ), 00117 1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) } 00118 }; 00119 00120 ply_get_property( file, "face", &faceProps[0] ); 00121 00122 triangles.clear(); 00123 triangles.reserve( nFaces ); 00124 00125 // read in the faces, asserting that they are only triangles 00126 uint8_t ind1 = _invertFaces ? 2 : 0; 00127 uint8_t ind3 = _invertFaces ? 0 : 2; 00128 for( int i = 0; i < nFaces; ++i ) 00129 { 00130 ply_get_element( file, static_cast< void* >( &face ) ); 00131 MESHASSERT( face.vertices != 0 ); 00132 if( face.nVertices != 3 ) 00133 { 00134 free( face.vertices ); 00135 throw MeshException( "Error reading PLY file. Encountered a " 00136 "face which does not have three vertices." ); 00137 } 00138 triangles.push_back( Triangle( face.vertices[ind1], 00139 face.vertices[1], 00140 face.vertices[ind3] ) ); 00141 00142 // free the memory that was allocated by ply_get_element 00143 free( face.vertices ); 00144 } 00145 } 00146 00147 00148 /* Open a PLY file and read vertex, color and index data. */ 00149 bool VertexData::readPlyFile( const std::string& filename ) 00150 { 00151 int nPlyElems; 00152 char** elemNames; 00153 int fileType; 00154 float version; 00155 bool result = false; 00156 00157 PlyFile* file = ply_open_for_reading( const_cast<char*>( filename.c_str( )), 00158 &nPlyElems, &elemNames, 00159 &fileType, &version ); 00160 if( !file ) 00161 { 00162 MESHERROR << "Unable to open PLY file " << filename 00163 << " for reading." << std::endl; 00164 return result; 00165 } 00166 MESHASSERT( elemNames != 0 ); 00167 00168 #ifndef NDEBUG 00169 MESHINFO << filename << ": " << nPlyElems << " elements, file type = " 00170 << fileType << ", version = " << version << std::endl; 00171 #endif 00172 00173 for( int i = 0; i < nPlyElems; ++i ) 00174 { 00175 int nElems; 00176 int nProps; 00177 00178 PlyProperty** props = ply_get_element_description( file, elemNames[i], 00179 &nElems, &nProps ); 00180 MESHASSERT( props != 0 ); 00181 00182 #ifndef NDEBUG 00183 MESHINFO << "element " << i << ": name = " << elemNames[i] << ", " 00184 << nProps << " properties, " << nElems << " elements" 00185 << std::endl; 00186 for( int j = 0; j < nProps; ++j ) 00187 { 00188 MESHINFO << "element " << i << ", property " << j << ": " 00189 << "name = " << props[j]->name << std::endl; 00190 } 00191 #endif 00192 00193 if( equal_strings( elemNames[i], "vertex" ) ) 00194 { 00195 bool hasColors = false; 00196 // determine if the file stores vertex colors 00197 for( int j = 0; j < nProps; ++j ) 00198 if( equal_strings( props[j]->name, "red" ) ) 00199 hasColors = true; 00200 00201 readVertices( file, nElems, hasColors ); 00202 MESHASSERT( vertices.size() == static_cast< size_t >( nElems ) ); 00203 if( hasColors ) 00204 { 00205 MESHASSERT( colors.size() == static_cast< size_t >( nElems )); 00206 } 00207 } 00208 else if( equal_strings( elemNames[i], "face" ) ) 00209 try 00210 { 00211 readTriangles( file, nElems ); 00212 MESHASSERT( triangles.size() == static_cast< size_t >( nElems ) ); 00213 result = true; 00214 } 00215 catch( const std::exception& e ) 00216 { 00217 MESHERROR << "Unable to read PLY file, an exception occured: " 00218 << e.what() << std::endl; 00219 // stop for loop by setting the loop variable to break condition 00220 // this way resources still get released even on error cases 00221 i = nPlyElems; 00222 } 00223 00224 // free the memory that was allocated by ply_get_element_description 00225 for( int j = 0; j < nProps; ++j ) 00226 free( props[j] ); 00227 free( props ); 00228 } 00229 00230 ply_close( file ); 00231 00232 // free the memory that was allocated by ply_open_for_reading 00233 for( int i = 0; i < nPlyElems; ++i ) 00234 free( elemNames[i] ); 00235 free( elemNames ); 00236 00237 return result; 00238 } 00239 00240 00241 /* Calculate the face or vertex normals of the current vertex data. */ 00242 void VertexData::calculateNormals() 00243 { 00244 #ifndef NDEBUG 00245 int wrongNormals = 0; 00246 #endif 00247 00248 normals.clear(); 00249 normals.reserve( vertices.size() ); 00250 00251 // initialize all normals to zero 00252 for( size_t i = 0; i < vertices.size(); ++i ) 00253 normals.push_back( Normal( 0, 0, 0 ) ); 00254 00255 // iterate over all triangles and add their normals to adjacent vertices 00256 #pragma omp parallel for 00257 for( ssize_t i = 0; i < ssize_t( triangles.size( )); ++i ) 00258 { 00259 const Index i0 = triangles[i][0]; 00260 const Index i1 = triangles[i][1]; 00261 const Index i2 = triangles[i][2]; 00262 const Normal normal = vertices[i0].compute_normal( vertices[i1], 00263 vertices[i2] ); 00264 #ifndef NDEBUG 00265 // count emtpy normals in debug mode 00266 if( normal.length() == 0.0f ) 00267 ++wrongNormals; // racy with OpenMP, but not critical 00268 #endif 00269 00270 normals[i0] += normal; 00271 normals[i1] += normal; 00272 normals[i2] += normal; 00273 } 00274 00275 // normalize all the normals 00276 #pragma omp parallel for 00277 for( ssize_t i = 0; i < ssize_t( vertices.size( )); ++i ) 00278 normals[i].normalize(); 00279 00280 #ifndef NDEBUG 00281 if( wrongNormals > 0 ) 00282 MESHINFO << wrongNormals << " faces have no valid normal." << std::endl; 00283 #endif 00284 } 00285 00286 00287 /* Calculate the bounding box of the current vertex data. */ 00288 void VertexData::calculateBoundingBox() 00289 { 00290 _boundingBox[0] = vertices[0]; 00291 _boundingBox[1] = vertices[0]; 00292 for( size_t v = 1; v < vertices.size(); ++v ) 00293 for( size_t i = 0; i < 3; ++i ) 00294 { 00295 _boundingBox[0][i] = std::min( _boundingBox[0][i], vertices[v][i] ); 00296 _boundingBox[1][i] = std::max( _boundingBox[1][i], vertices[v][i] ); 00297 } 00298 } 00299 00300 00301 /* Calculates longest axis for a set of triangles */ 00302 Axis VertexData::getLongestAxis( const size_t start, 00303 const size_t elements ) const 00304 { 00305 if( start + elements > triangles.size() ) 00306 { 00307 LBERROR << "incorrect request to getLongestAxis" << std::endl 00308 << "start: " << start << std::endl 00309 << "elements: " << elements << std::endl 00310 << "sum: " << start+elements << std::endl 00311 << "data size: " << triangles.size() << std::endl; 00312 return AXIS_X; 00313 } 00314 00315 BoundingBox bb; 00316 bb[0] = vertices[ triangles[start][0] ]; 00317 bb[1] = vertices[ triangles[start][0] ]; 00318 00319 for( size_t t = start; t < start+elements; ++t ) 00320 for( size_t v = 0; v < 3; ++v ) 00321 for( size_t i = 0; i < 3; ++i ) 00322 { 00323 bb[0][i] = std::min( bb[0][i], vertices[ triangles[t][v] ][i] ); 00324 bb[1][i] = std::max( bb[1][i], vertices[ triangles[t][v] ][i] ); 00325 } 00326 00327 const GLfloat bbX = bb[1][0] - bb[0][0]; 00328 const GLfloat bbY = bb[1][1] - bb[0][1]; 00329 const GLfloat bbZ = bb[1][2] - bb[0][2]; 00330 00331 if( bbX >= bbY && bbX >= bbZ ) 00332 return AXIS_X; 00333 00334 if( bbY >= bbX && bbY >= bbZ ) 00335 return AXIS_Y; 00336 00337 return AXIS_Z; 00338 } 00339 00340 00341 /* Scales the data to be within +- baseSize/2 (default 2.0) coordinates. */ 00342 void VertexData::scale( const float baseSize ) 00343 { 00344 // calculate bounding box if not yet done 00345 if( _boundingBox[0].length() == 0.0f && _boundingBox[1].length() == 0.0f ) 00346 calculateBoundingBox(); 00347 00348 // find largest dimension and determine scale factor 00349 float factor = 0.0f; 00350 for( size_t i = 0; i < 3; ++i ) 00351 factor = std::max( factor, _boundingBox[1][i] - _boundingBox[0][i] ); 00352 factor = baseSize / factor; 00353 00354 // determine scale offset 00355 Vertex offset; 00356 for( size_t i = 0; i < 3; ++i ) 00357 offset[i] = ( _boundingBox[0][i] + _boundingBox[1][i] ) * 0.5f; 00358 00359 // scale the data 00360 #pragma omp parallel for 00361 for( ssize_t v = 0; v < ssize_t( vertices.size( )); ++v ) 00362 for( size_t i = 0; i < 3; ++i ) 00363 { 00364 vertices[v][i] -= offset[i]; 00365 vertices[v][i] *= factor; 00366 } 00367 00368 // scale the bounding box 00369 for( size_t v = 0; v < 2; ++v ) 00370 for( size_t i = 0; i < 3; ++i ) 00371 { 00372 _boundingBox[v][i] -= offset[i]; 00373 _boundingBox[v][i] *= factor; 00374 } 00375 } 00376 00377 00379 /* Helper structure to sort Triangles with standard library sort function. */ 00380 struct _TriangleSort 00381 { 00382 _TriangleSort( const VertexData& data, const Axis axis ) : _data( data ), 00383 _axis( axis ) {} 00384 00385 bool operator() ( const Triangle& t1, const Triangle& t2 ) 00386 { 00387 // references to both triangles' three vertices 00388 const Vertex& v11 = _data.vertices[ t1[0] ]; 00389 const Vertex& v12 = _data.vertices[ t1[1] ]; 00390 const Vertex& v13 = _data.vertices[ t1[2] ]; 00391 const Vertex& v21 = _data.vertices[ t2[0] ]; 00392 const Vertex& v22 = _data.vertices[ t2[1] ]; 00393 const Vertex& v23 = _data.vertices[ t2[2] ]; 00394 00395 // compare first by given axis 00396 int axis = _axis; 00397 do 00398 { 00399 // test median of 'axis' component of all three vertices 00400 const float median1 = (v11[axis] + v12[axis] + v13[axis] ) / 3.0f; 00401 const float median2 = (v21[axis] + v22[axis] + v23[axis] ) / 3.0f; 00402 if( median1 != median2 ) 00403 return ( median1 < median2 ); 00404 00405 // if still equal, move on to the next axis 00406 axis = ( axis + 1 ) % 3; 00407 } 00408 while( axis != _axis ); 00409 00410 return false; 00411 } 00412 00413 const VertexData& _data; 00414 const Axis _axis; 00415 }; 00418 /* Sort the index data from start to start + length along the given axis. */ 00419 void VertexData::sort( const Index start, const Index length, const Axis axis ) 00420 { 00421 MESHASSERT( length > 0 ); 00422 MESHASSERT( start + length <= triangles.size() ); 00423 00424 ::sort( triangles.begin() + start, triangles.begin() + start + length, 00425 _TriangleSort( *this, axis ) ); 00426 }