00001
00002 #ifndef _MESHOBJ_H
00003 #define _MESHOBJ_H
00004
00005 #include <string>
00006
00007 namespace gk {
00008
00009 class Mesh;
00010
00011 bool isMeshOBJ( const std::string& filename );
00012
00013 int MeshLoadFromOBJ( const std::string& filename, Mesh *mesh );
00014 int MaterialLoadFromMTL( const std::string& filename );
00015
00016 int MeshWriteToOBJ( Mesh *mesh, const std::string& filename );
00017 int MeshMaterialsMTLLIB( const Mesh *mesh, std::string& mtllib );
00018 int MeshMaterialsWriteToMTL( const Mesh *mesh, const std::string& filename );
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 namespace OBJ
00029 {
00030
00031
00032 class Parser
00033 {
00034 FILE *m_in;
00035 std::string m_token;
00036
00037 bool is_token( const char c )
00038 {
00039 return ( isalnum( c ) || c == '_' || c == '-' || c == '.' );
00040 }
00041
00042 public:
00043 Parser( const std::string& filename )
00044 :
00045 m_in( NULL ),
00046 m_token()
00047 {
00048 m_in = fopen( filename.c_str(), "rt" );
00049 }
00050
00051 ~Parser( )
00052 {
00053 if ( m_in != NULL )
00054 fclose( m_in );
00055 }
00056
00057 bool isValid( ) const
00058 {
00059 return ( m_in != NULL );
00060 }
00061
00062
00063
00064
00065 int readToken( )
00066 {
00067 if ( !isValid() )
00068 return EOF;
00069
00070
00071 char c = fgetc( m_in );
00072 while ( c != EOF && ( c == ' ' || c == '\t' ) )
00073 c = fgetc( m_in );
00074
00075 if ( c == '\r' )
00076 c = '\n';
00077
00078
00079 m_token.resize( 0 );
00080 while ( c != EOF && is_token( c ) )
00081 {
00082 m_token.push_back( c );
00083
00084 c = fgetc( m_in );
00085 if ( c == '\r' )
00086 c = '\n';
00087 }
00088
00089
00090 if ( c == '#' )
00091 {
00092 if ( m_token.empty() )
00093 m_token.push_back( c );
00094 else
00095 ungetc( c, m_in );
00096 }
00097 else if ( c == '/' )
00098 m_token.push_back( c );
00099
00100
00101 if ( m_token.empty() )
00102 return c;
00103
00104
00105 if ( c == EOF )
00106 ungetc( '\n', m_in );
00107
00108 else if ( c == '\n' )
00109 ungetc( c, m_in );
00110
00111 return 0;
00112 }
00113
00114
00115 int readString( )
00116 {
00117 std::string string;
00118
00119
00120 #if 0
00121 while ( readToken() != '\n' )
00122 string += m_token;
00123 #else
00124
00125 int code = readToken();
00126 while ( code != '\n' )
00127 {
00128 string.append( m_token );
00129 if ( code != 0 )
00130 string.push_back( code );
00131 code = readToken();
00132 }
00133 #endif
00134
00135 assert( string.length() == strlen( string.c_str() ) );
00136
00137 m_token.swap( string );
00138 if ( m_token.empty() )
00139 return -1;
00140 else
00141 return 0;
00142 }
00143
00144
00145 const std::string& getToken( ) const
00146 {
00147 return m_token;
00148 }
00149
00150
00151 char getLastChar( ) const
00152 {
00153 const int length = ( int ) m_token.length();
00154 if ( length == 0 )
00155 return 0;
00156
00157 return m_token[length -1];
00158 }
00159
00160
00161 char getChar( const int i = 0 ) const
00162 {
00163 assert( i >= 0 && i < ( int ) m_token.length() );
00164 return m_token[i];
00165 }
00166
00167
00168 int getFloat( float& v ) const
00169 {
00170 v = 0.f;
00171 if ( sscanf( m_token.c_str(), "%f", &v ) != 1 )
00172 return -1;
00173 else
00174 return 0;
00175 }
00176
00177
00178 int getInt( int& v ) const
00179 {
00180 v = 0;
00181 if ( sscanf( m_token.c_str(), "%d", &v ) != 1 )
00182 return -1;
00183 else
00184 return 0;
00185 }
00186
00187
00188 int readVector3( Vector& v )
00189 {
00190 int i;
00191 for ( i = 0; readToken() != '\n'; i++ )
00192 if ( i < 3 && getFloat( v[i] ) < 0 )
00193 return -1;
00194
00195 if ( i != 3 )
00196 return -1;
00197 else
00198 return 0;
00199 }
00200
00201
00202 int readVector2( Point2& v )
00203 {
00204 int i;
00205 for ( i = 0; readToken() != '\n'; i++ )
00206 if ( i < 2 && getFloat( v[i] ) < 0 )
00207 return -1;
00208
00209 if ( i != 2 )
00210 return -1;
00211 else
00212 return 0;
00213 }
00214
00215
00216
00217 int skipLine( )
00218 {
00219 while ( readToken() != '\n' )
00220 {
00221 #ifdef VERBOSE_DEBUG
00222 printf("skip '%s'\n", getToken().c_str());
00223 #endif
00224 }
00225
00226 return 0;
00227 }
00228 };
00229
00230
00231
00232 inline
00233 int getAttribute( const Parser& parser, int& attr, const int attributes_n )
00234 {
00235 if ( parser.getChar( 0 ) == '/' )
00236 return 0;
00237
00238 if ( parser.getInt( attr ) < 0 )
00239 return -1;
00240
00241 if ( attr < 0 )
00242 attr += attributes_n;
00243 else
00244 attr -= 1;
00245
00246 if ( attr < 0 || attr >= attributes_n )
00247 return -1;
00248 else
00249 return 1;
00250 }
00251
00252
00253
00254 struct Vertex
00255 {
00256 int m_indices[4];
00257
00258 Vertex( ) {}
00259
00260 Vertex( const int m, const int p, const int n, const int t )
00261 {
00262 m_indices[0] = m;
00263 m_indices[1] = p;
00264 m_indices[2] = n;
00265 m_indices[3] = t;
00266 }
00267
00268 ~Vertex( ) {}
00269
00270
00271 static
00272 bool less( const Vertex& a, const Vertex& b )
00273 {
00274
00275 for ( int i = 0; i < 4; i++ )
00276 {
00277 if ( a.m_indices[i] < b.m_indices[i] )
00278
00279 return true;
00280 else if ( a.m_indices[i] > b.m_indices[i] )
00281 return false;
00282 }
00283
00284 return false;
00285 }
00286
00287
00288 int material( ) const
00289 {
00290 return m_indices[0];
00291 }
00292
00293
00294 int position( ) const
00295 {
00296 return m_indices[1];
00297 }
00298
00299
00300 int normal( ) const
00301 {
00302 return m_indices[2];
00303 }
00304
00305
00306 int texcoord( ) const
00307 {
00308 return m_indices[3];
00309 }
00310 };
00311
00312
00313 inline
00314 bool operator<( const Vertex& a, const Vertex& b )
00315 {
00316 return Vertex::less( a, b );
00317 }
00318
00319
00320 struct Triangle
00321 {
00322 int m_indices[3];
00323 int m_material_id;
00324 int m_smooth_id;
00325
00326
00327 Triangle( )
00328 :
00329 m_material_id( -1 ),
00330 m_smooth_id( -1 )
00331 {}
00332
00333
00334 ~Triangle( ) {}
00335
00336
00337 Triangle( const int a, const int b, const int c )
00338 {
00339 m_indices[0] = a;
00340 m_indices[1] = b;
00341 m_indices[2] = c;
00342 }
00343
00344
00345 void setMaterial( const int id )
00346 {
00347 m_material_id = id;
00348 }
00349
00350
00351 void setSmoothGroup( const int group_id )
00352 {
00353 m_smooth_id = group_id;
00354 }
00355
00356
00357 int a( ) const
00358 {
00359 return m_indices[0];
00360 }
00361
00362
00363 int b( ) const
00364 {
00365 return m_indices[1];
00366 }
00367
00368
00369 int c( ) const
00370 {
00371 return m_indices[2];
00372 }
00373
00374
00375 int material( ) const
00376 {
00377 return m_material_id;
00378 }
00379
00380
00381 int smoothGroup( ) const
00382 {
00383 return m_smooth_id;
00384 }
00385
00386
00387 static
00388 bool material_less( const Triangle& a, const Triangle& b )
00389 {
00390 return ( a.material() < b.material() );
00391 }
00392 };
00393
00394 }
00395
00396 }
00397
00398 #endif