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