|
Equalizer
1.3.1-git
|
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 00044 using namespace std; 00045 using namespace mesh; 00046 00047 00048 /* Contructor. */ 00049 VertexData::VertexData() 00050 : _invertFaces( false ) 00051 { 00052 _boundingBox[0] = Vertex( 0.0f ); 00053 _boundingBox[1] = Vertex( 0.0f ); 00054 } 00055 00056 00057 /* Read the vertex and (if available/wanted) color data from the open file. */ 00058 void VertexData::readVertices( PlyFile* file, const int nVertices, 00059 const bool readColors ) 00060 { 00061 // temporary vertex structure for ply loading 00062 struct _Vertex 00063 { 00064 float x; 00065 float y; 00066 float z; 00067 unsigned char r; 00068 unsigned char g; 00069 unsigned char b; 00070 } vertex; 00071 00072 PlyProperty vertexProps[] = 00073 { 00074 { "x", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, x ), 0, 0, 0, 0 }, 00075 { "y", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, y ), 0, 0, 0, 0 }, 00076 { "z", PLY_FLOAT, PLY_FLOAT, offsetof( _Vertex, z ), 0, 0, 0, 0 }, 00077 { "red", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, r ), 0, 0, 0, 0 }, 00078 { "green", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, g ), 0, 0, 0, 0 }, 00079 { "blue", PLY_UCHAR, PLY_UCHAR, offsetof( _Vertex, b ), 0, 0, 0, 0 } 00080 }; 00081 00082 // use all 6 properties when reading colors, only the first 3 otherwise 00083 int limit = readColors ? 6 : 3; 00084 for( int i = 0; i < limit; ++i ) 00085 ply_get_property( file, "vertex", &vertexProps[i] ); 00086 00087 vertices.clear(); 00088 vertices.reserve( nVertices ); 00089 00090 if( readColors ) 00091 { 00092 colors.clear(); 00093 colors.reserve( nVertices ); 00094 } 00095 00096 // read in the vertices 00097 for( int i = 0; i < nVertices; ++i ) 00098 { 00099 ply_get_element( file, static_cast< void* >( &vertex ) ); 00100 vertices.push_back( Vertex( vertex.x, vertex.y, vertex.z ) ); 00101 if( readColors ) 00102 colors.push_back( Color( vertex.r, vertex.g, vertex.b, 0 ) ); 00103 } 00104 } 00105 00106 00107 /* Read the index data from the open file. */ 00108 void VertexData::readTriangles( PlyFile* file, const int nFaces ) 00109 { 00110 // temporary face structure for ply loading 00111 struct _Face 00112 { 00113 unsigned char nVertices; 00114 int* vertices; 00115 } face; 00116 00117 PlyProperty faceProps[] = 00118 { 00119 { "vertex_indices", PLY_INT, PLY_INT, offsetof( _Face, vertices ), 00120 1, PLY_UCHAR, PLY_UCHAR, offsetof( _Face, nVertices ) } 00121 }; 00122 00123 ply_get_property( file, "face", &faceProps[0] ); 00124 00125 triangles.clear(); 00126 triangles.reserve( nFaces ); 00127 00128 // read in the faces, asserting that they are only triangles 00129 uint8_t ind1 = _invertFaces ? 2 : 0; 00130 uint8_t ind3 = _invertFaces ? 0 : 2; 00131 for( int i = 0; i < nFaces; ++i ) 00132 { 00133 ply_get_element( file, static_cast< void* >( &face ) ); 00134 MESHASSERT( face.vertices != 0 ); 00135 if( face.nVertices != 3 ) 00136 { 00137 free( face.vertices ); 00138 throw MeshException( "Error reading PLY file. Encountered a " 00139 "face which does not have three vertices." ); 00140 } 00141 triangles.push_back( Triangle( face.vertices[ind1], 00142 face.vertices[1], 00143 face.vertices[ind3] ) ); 00144 00145 // free the memory that was allocated by ply_get_element 00146 free( face.vertices ); 00147 } 00148 } 00149 00150 00151 /* Open a PLY file and read vertex, color and index data. */ 00152 bool VertexData::readPlyFile( const std::string& filename ) 00153 { 00154 int nPlyElems; 00155 char** elemNames; 00156 int fileType; 00157 float version; 00158 bool result = false; 00159 00160 PlyFile* file = ply_open_for_reading( const_cast<char*>( filename.c_str( )), 00161 &nPlyElems, &elemNames, 00162 &fileType, &version ); 00163 if( !file ) 00164 { 00165 MESHERROR << "Unable to open PLY file " << filename 00166 << " for reading." << endl; 00167 return result; 00168 } 00169 MESHASSERT( elemNames != 0 ); 00170 00171 #ifndef NDEBUG 00172 MESHINFO << filename << ": " << nPlyElems << " elements, file type = " 00173 << fileType << ", version = " << version << endl; 00174 #endif 00175 00176 for( int i = 0; i < nPlyElems; ++i ) 00177 { 00178 int nElems; 00179 int nProps; 00180 00181 PlyProperty** props = ply_get_element_description( file, elemNames[i], 00182 &nElems, &nProps ); 00183 MESHASSERT( props != 0 ); 00184 00185 #ifndef NDEBUG 00186 MESHINFO << "element " << i << ": name = " << elemNames[i] << ", " 00187 << nProps << " properties, " << nElems << " elements" << endl; 00188 for( int j = 0; j < nProps; ++j ) 00189 { 00190 MESHINFO << "element " << i << ", property " << j << ": " 00191 << "name = " << props[j]->name << endl; 00192 } 00193 #endif 00194 00195 if( equal_strings( elemNames[i], "vertex" ) ) 00196 { 00197 bool hasColors = false; 00198 // determine if the file stores vertex colors 00199 for( int j = 0; j < nProps; ++j ) 00200 if( equal_strings( props[j]->name, "red" ) ) 00201 hasColors = true; 00202 00203 readVertices( file, nElems, hasColors ); 00204 MESHASSERT( vertices.size() == static_cast< size_t >( nElems ) ); 00205 if( hasColors ) 00206 { 00207 MESHASSERT( colors.size() == static_cast< size_t >( nElems )); 00208 } 00209 } 00210 else if( equal_strings( elemNames[i], "face" ) ) 00211 try 00212 { 00213 readTriangles( file, nElems ); 00214 MESHASSERT( triangles.size() == static_cast< size_t >( nElems ) ); 00215 result = true; 00216 } 00217 catch( const exception& e ) 00218 { 00219 MESHERROR << "Unable to read PLY file, an exception occured: " 00220 << e.what() << endl; 00221 // stop for loop by setting the loop variable to break condition 00222 // this way resources still get released even on error cases 00223 i = nPlyElems; 00224 } 00225 00226 // free the memory that was allocated by ply_get_element_description 00227 for( int j = 0; j < nProps; ++j ) 00228 free( props[j] ); 00229 free( props ); 00230 } 00231 00232 ply_close( file ); 00233 00234 // free the memory that was allocated by ply_open_for_reading 00235 for( int i = 0; i < nPlyElems; ++i ) 00236 free( elemNames[i] ); 00237 free( elemNames ); 00238 00239 return result; 00240 } 00241 00242 00243 /* Calculate the face or vertex normals of the current vertex data. */ 00244 void VertexData::calculateNormals() 00245 { 00246 #ifndef NDEBUG 00247 int wrongNormals = 0; 00248 #endif 00249 00250 normals.clear(); 00251 normals.reserve( vertices.size() ); 00252 00253 // initialize all normals to zero 00254 for( size_t i = 0; i < vertices.size(); ++i ) 00255 normals.push_back( Normal( 0, 0, 0 ) ); 00256 00257 // iterate over all triangles and add their normals to adjacent vertices 00258 #pragma omp parallel for 00259 for( ssize_t i = 0; i < ssize_t( triangles.size( )); ++i ) 00260 { 00261 const Index i0 = triangles[i][0]; 00262 const Index i1 = triangles[i][1]; 00263 const Index i2 = triangles[i][2]; 00264 const Normal normal = vertices[i0].compute_normal( vertices[i1], 00265 vertices[i2] ); 00266 #ifndef NDEBUG 00267 // count emtpy normals in debug mode 00268 if( normal.length() == 0.0f ) 00269 ++wrongNormals; // racy with OpenMP, but not critical 00270 #endif 00271 00272 normals[i0] += normal; 00273 normals[i1] += normal; 00274 normals[i2] += normal; 00275 } 00276 00277 // normalize all the normals 00278 #pragma omp parallel for 00279 for( ssize_t i = 0; i < ssize_t( vertices.size( )); ++i ) 00280 normals[i].normalize(); 00281 00282 #ifndef NDEBUG 00283 if( wrongNormals > 0 ) 00284 MESHINFO << wrongNormals << " faces have no valid normal." << endl; 00285 #endif 00286 } 00287 00288 00289 /* Calculate the bounding box of the current vertex data. */ 00290 void VertexData::calculateBoundingBox() 00291 { 00292 _boundingBox[0] = vertices[0]; 00293 _boundingBox[1] = vertices[0]; 00294 for( size_t v = 1; v < vertices.size(); ++v ) 00295 for( size_t i = 0; i < 3; ++i ) 00296 { 00297 _boundingBox[0][i] = min( _boundingBox[0][i], vertices[v][i] ); 00298 _boundingBox[1][i] = max( _boundingBox[1][i], vertices[v][i] ); 00299 } 00300 } 00301 00302 00303 /* Calculates longest axis for a set of triangles */ 00304 Axis VertexData::getLongestAxis( const size_t start, 00305 const size_t elements ) const 00306 { 00307 if( start + elements > triangles.size() ) 00308 { 00309 LBERROR << "incorrect request to getLongestAxis" << endl 00310 << "start: " << start << endl 00311 << "elements: " << elements << endl 00312 << "sum: " << start+elements << endl 00313 << "data size: " << triangles.size() << endl; 00314 return AXIS_X; 00315 } 00316 00317 BoundingBox bb; 00318 bb[0] = vertices[ triangles[start][0] ]; 00319 bb[1] = vertices[ triangles[start][0] ]; 00320 00321 for( size_t t = start; t < start+elements; ++t ) 00322 for( size_t v = 0; v < 3; ++v ) 00323 for( size_t i = 0; i < 3; ++i ) 00324 { 00325 bb[0][i] = min( bb[0][i], vertices[ triangles[t][v] ][i] ); 00326 bb[1][i] = max( bb[1][i], vertices[ triangles[t][v] ][i] ); 00327 } 00328 00329 const GLfloat bbX = bb[1][0] - bb[0][0]; 00330 const GLfloat bbY = bb[1][1] - bb[0][1]; 00331 const GLfloat bbZ = bb[1][2] - bb[0][2]; 00332 00333 if( bbX >= bbY && bbX >= bbZ ) 00334 return AXIS_X; 00335 00336 if( bbY >= bbX && bbY >= bbZ ) 00337 return AXIS_Y; 00338 00339 return AXIS_Z; 00340 } 00341 00342 00343 /* Scales the data to be within +- baseSize/2 (default 2.0) coordinates. */ 00344 void VertexData::scale( const float baseSize ) 00345 { 00346 // calculate bounding box if not yet done 00347 if( _boundingBox[0].length() == 0.0f && _boundingBox[1].length() == 0.0f ) 00348 calculateBoundingBox(); 00349 00350 // find largest dimension and determine scale factor 00351 float factor = 0.0f; 00352 for( size_t i = 0; i < 3; ++i ) 00353 factor = max( factor, _boundingBox[1][i] - _boundingBox[0][i] ); 00354 factor = baseSize / factor; 00355 00356 // determine scale offset 00357 Vertex offset; 00358 for( size_t i = 0; i < 3; ++i ) 00359 offset[i] = ( _boundingBox[0][i] + _boundingBox[1][i] ) * 0.5f; 00360 00361 // scale the data 00362 #pragma omp parallel for 00363 for( ssize_t v = 0; v < ssize_t( vertices.size( )); ++v ) 00364 for( size_t i = 0; i < 3; ++i ) 00365 { 00366 vertices[v][i] -= offset[i]; 00367 vertices[v][i] *= factor; 00368 } 00369 00370 // scale the bounding box 00371 for( size_t v = 0; v < 2; ++v ) 00372 for( size_t i = 0; i < 3; ++i ) 00373 { 00374 _boundingBox[v][i] -= offset[i]; 00375 _boundingBox[v][i] *= factor; 00376 } 00377 } 00378 00379 00381 /* Helper structure to sort Triangles with standard library sort function. */ 00382 struct _TriangleSort 00383 { 00384 _TriangleSort( const VertexData& data, const Axis axis ) : _data( data ), 00385 _axis( axis ) {} 00386 00387 bool operator() ( const Triangle& t1, const Triangle& t2 ) 00388 { 00389 // references to both triangles' three vertices 00390 const Vertex& v11 = _data.vertices[ t1[0] ]; 00391 const Vertex& v12 = _data.vertices[ t1[1] ]; 00392 const Vertex& v13 = _data.vertices[ t1[2] ]; 00393 const Vertex& v21 = _data.vertices[ t2[0] ]; 00394 const Vertex& v22 = _data.vertices[ t2[1] ]; 00395 const Vertex& v23 = _data.vertices[ t2[2] ]; 00396 00397 // compare first by given axis 00398 int axis = _axis; 00399 do 00400 { 00401 // test median of 'axis' component of all three vertices 00402 const float median1 = (v11[axis] + v12[axis] + v13[axis] ) / 3.0f; 00403 const float median2 = (v21[axis] + v22[axis] + v23[axis] ) / 3.0f; 00404 if( median1 != median2 ) 00405 return ( median1 < median2 ); 00406 00407 // if still equal, move on to the next axis 00408 axis = ( axis + 1 ) % 3; 00409 } 00410 while( axis != _axis ); 00411 00412 return false; 00413 } 00414 00415 const VertexData& _data; 00416 const Axis _axis; 00417 }; 00420 /* Sort the index data from start to start + length along the given axis. */ 00421 void VertexData::sort( const Index start, const Index length, const Axis axis ) 00422 { 00423 MESHASSERT( length > 0 ); 00424 MESHASSERT( start + length <= triangles.size() ); 00425 00426 ::sort( triangles.begin() + start, triangles.begin() + start + length, 00427 _TriangleSort( *this, axis ) ); 00428 }
1.3.1-git by
1.8.0