OpenWalnut  1.5.0dev
WMeshReaderOBJ.cpp
1 //---------------------------------------------------------------------------
2 //
3 // Project: OpenWalnut ( http://www.openwalnut.org )
4 //
5 // Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-CBS
6 // For more information see http://www.openwalnut.org/copying
7 //
8 // This file is part of OpenWalnut.
9 //
10 // OpenWalnut is free software: you can redistribute it and/or modify
11 // it under the terms of the GNU Lesser General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // OpenWalnut is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Lesser General Public License for more details.
19 //
20 // You should have received a copy of the GNU Lesser General Public License
21 // along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
22 //
23 //---------------------------------------------------------------------------
24 
25 #include <memory>
26 #include <string>
27 #include <vector>
28 
29 #include <boost/regex.hpp>
30 
31 #include "WMeshReaderOBJ.h"
32 
34  WObjectNDIP< WMeshReaderInterface >( "OBJ", "Load OBJ Meshes." )
35 {
36  // add properties
37 }
38 
40 {
41  // cleanup
42 }
43 
45  boost::filesystem::path file )
46 {
47  // open the file
48  std::string fileName = file.string();
49  WAssert( !fileName.empty(), "No filename specified." );
50 
51  std::shared_ptr< WProgress > progress( new WProgress( "Read Mesh" ) );
52  parentProgress->addSubProgress( progress );
53 
54  std::ifstream ifs;
55  ifs.open( fileName.c_str(), std::ifstream::in );
56  if( !ifs || ifs.bad() )
57  {
58  throw WDHIOFailure( "Could not open \"" + fileName + "\" for reading." );
59  }
60 
61  // regex for the different lines possible in OBJ
62  // mateches vertex only
63  static const boost::regex faceVRegex( "^ *[f,F] *([0-9]+) +([0-9]+) +([0-9]+).*$" );
64  // matches vertex-tex coord
65  static const boost::regex faceVTRegex( "^ *[f,F] *([0-9]+)/([0-9]+) +([0-9]+)/([0-9]+) +([0-9]+)/([0-9]+).*$" );
66  // matches vertex-tex coord-normal
67  static const boost::regex faceVTNRegex( "^ *[f,F] *([0-9]+)/([0-9]+)/([0-9]+) +([0-9]+)/([0-9]+)/([0-9]+) +([0-9]+)/([0-9]+)/([0-9]+).*$" );
68  // matches vertex-normal
69  static const boost::regex faceVNRegex( "^ *[f,F] *([0-9]+)//([0-9]+) +([0-9]+)//([0-9]+) +([0-9]+)//([0-9]+).*$" );
70 
71  static const boost::regex vertexRegex( "^ *[v,V][^n] *(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*).*$" );
72  static const boost::regex vertexColorRegex( "^ *[v,V][^n] *(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*) (-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*).*$" ); // NOLINT
73  static const boost::regex normalRegex( "^ *[v,V][n,N] *(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*) +(-?[0-9]*\\.?[0-9]*).*$" );
74  static const boost::regex commentRegex( "^ *#.*$" );
75  // please note that there are several more possible definitions ... Please see http://en.wikipedia.org/wiki/Wavefront_.obj_file
76 
77  // read contents
78  size_t numUnsupported = 0;
79  std::string line = "";
80 
81  std::vector< float > vertices;
82  std::vector< float > colors;
83  std::vector< size_t > faces;
84  std::vector< size_t > normals;
85 
86  vertices.reserve( 3000 );
87  faces.reserve( 3000 );
88 
89  // read line by line
90  while( !ifs.eof() )
91  {
92  // get the line
93  std::getline( ifs, line, '\n' );
94 
95  // ignore empty lines
96  if( !line.size() )
97  {
98  // empty line
99  continue;
100  }
101 
102  // for interpreting the lines, we utilize boost::regex here
103  boost::smatch matches; // the list of matches
104 
105  // check whether this is a vertex definition
106  if( boost::regex_match( line, matches, vertexColorRegex ) )
107  {
108  vertices.push_back( string_utils::fromString< float >( matches[1] ) );
109  vertices.push_back( string_utils::fromString< float >( matches[2] ) );
110  vertices.push_back( string_utils::fromString< float >( matches[3] ) );
111  colors.push_back( string_utils::fromString< float >( matches[4] ) );
112  colors.push_back( string_utils::fromString< float >( matches[5] ) );
113  colors.push_back( string_utils::fromString< float >( matches[6] ) );
114  }
115  else if( boost::regex_match( line, matches, vertexRegex ) )
116  {
117  vertices.push_back( string_utils::fromString< float >( matches[1] ) );
118  vertices.push_back( string_utils::fromString< float >( matches[2] ) );
119  vertices.push_back( string_utils::fromString< float >( matches[3] ) );
120  }
121  else if( boost::regex_match( line, matches, normalRegex ) )
122  {
123  normals.push_back( string_utils::fromString< float >( matches[1] ) );
124  normals.push_back( string_utils::fromString< float >( matches[2] ) );
125  normals.push_back( string_utils::fromString< float >( matches[3] ) );
126  }
127  // check whether this is a face definition
128  else if( boost::regex_match( line, matches, faceVRegex ) )
129  {
130  // NOTE: indices are stored beginning at 1
131  faces.push_back( string_utils::fromString< size_t >( matches[1] ) - 1 );
132  faces.push_back( string_utils::fromString< size_t >( matches[2] ) - 1 );
133  faces.push_back( string_utils::fromString< size_t >( matches[3] ) - 1 );
134  }
135  else if( boost::regex_match( line, matches, faceVTRegex ) )
136  {
137  // NOTE: indices are stored beginning at 1
138  faces.push_back( string_utils::fromString< size_t >( matches[1] ) - 1 );
139  faces.push_back( string_utils::fromString< size_t >( matches[3] ) - 1 );
140  faces.push_back( string_utils::fromString< size_t >( matches[5] ) - 1 );
141  }
142  else if( boost::regex_match( line, matches, faceVTNRegex ) )
143  {
144  // NOTE: indices are stored beginning at 1
145  faces.push_back( string_utils::fromString< size_t >( matches[1] ) - 1 );
146  faces.push_back( string_utils::fromString< size_t >( matches[4] ) - 1 );
147  faces.push_back( string_utils::fromString< size_t >( matches[7] ) - 1 );
148  }
149  else if( boost::regex_match( line, matches, faceVNRegex ) )
150  {
151  // NOTE: indices are stored beginning at 1
152  faces.push_back( string_utils::fromString< size_t >( matches[1] ) - 1 );
153  faces.push_back( string_utils::fromString< size_t >( matches[3] ) - 1 );
154  faces.push_back( string_utils::fromString< size_t >( matches[5] ) - 1 );
155  }
156  // check whether this is a comment
157  else if( boost::regex_match( line, matches, commentRegex ) )
158  {
159  // ignore them
160  }
161  // check whether this is something else
162  else
163  {
164  numUnsupported++;
165  }
166  }
167 
168  if( numUnsupported )
169  {
170  wlog::error( "Read Mesh" ) << "There where " << numUnsupported << " unsupported lines.";
171  }
172 
173  // done. Close file.
174  ifs.close();
175 
176  // build triMesh instance
177  WTriangleMesh::SPtr triMesh( new WTriangleMesh( vertices.size() / 3, faces.size() / 3 ) );
178  // this is needed if you want to keep the normals that have been loaded.
179  //triMesh->setAutoRecalcNormals( false );
180 
181  WAssert( ( vertices.size() == normals.size() ) || ( normals.size() == 0 ), "Number of normals and vertices do not match." );
182 
183  for( size_t i = 0; i < vertices.size(); i += 3 )
184  {
185  triMesh->addVertex( vertices[ i + 0 ], vertices[ i + 1 ], vertices[ i + 2 ] );
186  }
187  for( size_t i = 0; i < faces.size(); i += 3 )
188  {
189  triMesh->addTriangle( faces[ i + 0 ], faces[ i + 1 ], faces[ i + 2 ] );
190  }
191  for( size_t i = 0; i < normals.size(); i += 3 )
192  {
193  triMesh->setVertexNormal( i / 3, normals[ i + 0 ], normals[ i + 1 ], normals[ i + 2 ] );
194  }
195  for( size_t i = 0; i < colors.size(); i += 3 )
196  {
197  triMesh->setVertexColor( i / 3, osg::Vec4( colors[ i + 0 ], colors[ i + 1 ], colors[ i + 2 ], 1.0 ) );
198  }
199 
200  // done.
201  progress->finish();
202  parentProgress->removeSubProgress( progress );
203 
204  return triMesh;
205 }
Use this for IO error handling.
Definition: WDHIOFailure.h:38
Define the interface which is injected into an WObjectNDIP.
WMeshReaderOBJ()
Constructor.
virtual ~WMeshReaderOBJ()
Destructor.
virtual WTriangleMesh::SPtr operator()(WProgressCombiner::SPtr parentProgress, boost::filesystem::path file)
Load the dataset.
This is a base class for everything which has a Name,Description,Icon and Properties (=NDIP).
Definition: WObjectNDIP.h:42
std::shared_ptr< WProgressCombiner > SPtr
Abbreviate shared_ptr for this class.
Class managing progress inside of modules.
Definition: WProgress.h:42
Triangle mesh data structure allowing for convenient access of the elements.
Definition: WTriangleMesh.h:46
std::shared_ptr< WTriangleMesh > SPtr
Shared pointer.
Definition: WTriangleMesh.h:55
WStreamedLogger error(const std::string &source)
Logging an error message.
Definition: WLogger.h:298