gKitGL
|
00001 00002 #ifndef _MESHOBJ_H 00003 #define _MESHOBJ_H 00004 00005 #include <string> 00006 00007 namespace gk { 00008 00009 class Mesh; 00010 //! renvoie vrai si 'filename' se termine par '.obj'. 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 #if 0 00021 //! namespace prive. 00022 /*! namespace prive, pour isoler les classes utilisees pour charger les objets maya .obj et leurs matieres .mtl. 00023 00024 chargement d'un objet maya obj + construction lineaire d'un maillage triangule. 00025 00026 cf http://local.wasp.uwa.edu.au/~pbourke/dataformats/obj/ 00027 et http://local.wasp.uwa.edu.au/~pbourke/dataformats/mtl/ 00028 */ 00029 namespace OBJ 00030 { 00031 00032 //! parser pour analyser les fichiers obj et mtl. 00033 class Parser 00034 { 00035 FILE *m_in; 00036 std::string m_token; 00037 00038 bool is_token( const char c ) 00039 { 00040 return ( isalnum( c ) || c == '_' || c == '-' || c == '.' ); 00041 } 00042 00043 public: 00044 Parser( const std::string& filename ) 00045 : 00046 m_in( NULL ), 00047 m_token() 00048 { 00049 m_in = fopen( filename.c_str(), "rt" ); 00050 } 00051 00052 ~Parser( ) 00053 { 00054 if ( m_in != NULL ) 00055 fclose( m_in ); 00056 } 00057 00058 bool isValid( ) const 00059 { 00060 return ( m_in != NULL ); 00061 } 00062 00063 //! lecture sequentielle d'un 'mot' dans le fichier. 00064 //! un mot est un ensemble de caracteres quelconques delimite par des separateurs. 00065 //! renvoie le separateur, si la lecture d'un mot est impossible. 00066 int readToken( ) 00067 { 00068 if ( !isValid() ) 00069 return EOF; 00070 00071 // sauter les blancs 00072 char c = fgetc( m_in ); 00073 while ( c != EOF && ( c == ' ' || c == '\t' ) ) 00074 c = fgetc( m_in ); 00075 00076 if ( c == '\r' ) 00077 c = '\n'; // meme gestion des fins de lignes pour linux, mac et windows 00078 00079 // lire tous les caracteres alphanumeriques 00080 m_token.resize( 0 ); 00081 while ( c != EOF && is_token( c ) ) 00082 { 00083 m_token.push_back( c ); 00084 00085 c = fgetc( m_in ); 00086 if ( c == '\r' ) 00087 c = '\n'; // meme gestion des fins de lignes pour linux, mac et windows 00088 } 00089 00090 // separateurs 00091 if ( c == '#' ) 00092 { 00093 if ( m_token.empty() ) 00094 m_token.push_back( c ); 00095 else 00096 ungetc( c, m_in ); 00097 } 00098 else if ( c == '/' ) // ambiguite sur les noms de fichiers ... 00099 m_token.push_back( c ); 00100 00101 // indiquer la fin de la ligne ou du fichier 00102 if ( m_token.empty() ) 00103 return c; 00104 00105 // forcer une fin de ligne avant la fin du fichier 00106 if ( c == EOF ) 00107 ungetc( '\n', m_in ); 00108 00109 else if ( c == '\n' ) 00110 ungetc( c, m_in ); 00111 00112 return 0; 00113 } 00114 00115 //! lecture de la fin de la ligne, renvoie la chaine de caracteres. 00116 int readString( ) 00117 { 00118 std::string string; 00119 00120 // concatene tous les tokens jusqu'a la fin de la ligne 00121 #if 0 00122 while ( readToken() != '\n' ) 00123 string += m_token; 00124 #else 00125 // ajoute aussi les separateurs dans la chaine ... 00126 int code = readToken(); 00127 while ( code != '\n' ) 00128 { 00129 string.append( m_token ); 00130 if ( code != 0 ) 00131 string.push_back( code ); 00132 code = readToken(); 00133 } 00134 #endif 00135 00136 assert( string.length() == strlen( string.c_str() ) ); 00137 00138 m_token.swap( string ); 00139 if ( m_token.empty() ) 00140 return -1; 00141 else 00142 return 0; 00143 } 00144 00145 //! renvoie le dernier 'mot' lu par readToken(). 00146 const std::string& getToken( ) const 00147 { 00148 return m_token; 00149 } 00150 00151 //! renvoie le dernier caractere du dernier 'mot' lu. 00152 char getLastChar( ) const 00153 { 00154 const int length = ( int ) m_token.length(); 00155 if ( length == 0 ) 00156 return 0; 00157 00158 return m_token[length -1]; 00159 } 00160 00161 //! renvoie un caractere du dernier 'mot' lu. 00162 char getChar( const int i = 0 ) const 00163 { 00164 assert( i >= 0 && i < ( int ) m_token.length() ); 00165 return m_token[i]; 00166 } 00167 00168 //! converti le dernier 'mot' lu en reel. 00169 int getFloat( float& v ) const 00170 { 00171 v = 0.f; 00172 if ( sscanf( m_token.c_str(), "%f", &v ) != 1 ) 00173 return -1; 00174 else 00175 return 0; 00176 } 00177 00178 //! converti le dernier 'mot' lu en entier. 00179 int getInt( int& v ) const 00180 { 00181 v = 0; 00182 if ( sscanf( m_token.c_str(), "%d", &v ) != 1 ) 00183 return -1; 00184 else 00185 return 0; 00186 } 00187 00188 //! lit un vecteur 3. 00189 int readVector3( Vector& v ) 00190 { 00191 int i; 00192 for ( i = 0; readToken() != '\n'; i++ ) 00193 if ( i < 3 && getFloat( v[i] ) < 0 ) 00194 return -1; 00195 00196 if ( i < 3 ) 00197 return -1; 00198 else 00199 return 0; 00200 } 00201 00202 //! lit un vecteur 2. 00203 int readVector2( Point2& v ) 00204 { 00205 int i; 00206 for ( i = 0; readToken() != '\n'; i++ ) 00207 if ( i < 2 && getFloat( v[i] ) < 0 ) 00208 return -1; 00209 00210 if ( i < 2 ) 00211 return -1; 00212 else 00213 return 0; 00214 } 00215 00216 //! saute la ligne. 00217 //! lecture de tous les 'mots' jusqu'a la fin de la ligne. 00218 int skipLine( ) 00219 { 00220 while ( readToken() != '\n' ) 00221 { 00222 #ifdef VERBOSE_DEBUG 00223 printf("skip '%s'\n", getToken().c_str()); 00224 #endif 00225 } 00226 00227 return 0; 00228 } 00229 }; 00230 00231 //! determine l'indice d'un attribut de sommet dans le maillage. 00232 //! renvoie 0 si l'attribut n'existe pas, 1 si l'attribut existe et -1 en cas d'erreur. 00233 inline 00234 int getAttribute( const Parser& parser, int& attr, const int attributes_n ) 00235 { 00236 if ( parser.getChar( 0 ) == '/' ) 00237 return 0; 00238 00239 if ( parser.getInt( attr ) < 0 ) 00240 return -1; 00241 00242 if ( attr < 0 ) 00243 attr += attributes_n; 00244 else 00245 attr -= 1; 00246 00247 if ( attr < 0 || attr >= attributes_n ) 00248 return -1; 00249 else 00250 return 1; 00251 } 00252 00253 00254 //! representation d'un sommet, indice de matiere + triplet d'indices position, normale et texcoord. 00255 struct Vertex 00256 { 00257 int m_indices[4]; 00258 00259 Vertex( ) {} 00260 00261 Vertex( const int m, const int p, const int n, const int t ) 00262 { 00263 m_indices[0] = m; 00264 m_indices[1] = p; 00265 m_indices[2] = n; 00266 m_indices[3] = t; 00267 } 00268 00269 ~Vertex( ) {} 00270 00271 //! comparaison de 2 sommets pour l'insertion dans une std::map. 00272 static 00273 bool less( const Vertex& a, const Vertex& b ) 00274 { 00275 // definit un ordre lexicographique sur la matiere + les 3 indices : position, normale, texcoord 00276 for ( int i = 0; i < 4; i++ ) 00277 { 00278 if ( a.m_indices[i] < b.m_indices[i] ) 00279 // renvoie vrai lorsque a < b 00280 return true; 00281 else if ( a.m_indices[i] > b.m_indices[i] ) 00282 return false; 00283 } 00284 00285 return false; 00286 } 00287 00288 //! renvoie l'indice de la matiere du sommet. 00289 int material( ) const 00290 { 00291 return m_indices[0]; 00292 } 00293 00294 //! renvoie l'indice de la position du sommet. 00295 int position( ) const 00296 { 00297 return m_indices[1]; 00298 } 00299 00300 //! renvoie l'indice de la normale du sommet. 00301 int normal( ) const 00302 { 00303 return m_indices[2]; 00304 } 00305 00306 //! renvoie l'indice de la coordonnee de texture du sommet. 00307 int texcoord( ) const 00308 { 00309 return m_indices[3]; 00310 } 00311 }; 00312 00313 //! operateur de comparaison pour l'insertion d'un Vertex dans une std::map. 00314 inline 00315 bool operator<( const Vertex& a, const Vertex& b ) 00316 { 00317 return Vertex::less( a, b ); 00318 } 00319 00320 //! representation d'un triangle <abc> pour le maillage. 00321 struct Triangle 00322 { 00323 int m_indices[3]; 00324 int m_material_id; // a stocker a part ... cf. construction de l'index buffer 00325 int m_smooth_id; 00326 00327 //! contructeur par defaut. 00328 Triangle( ) 00329 : 00330 m_material_id( -1 ), 00331 m_smooth_id( -1 ) 00332 {} 00333 00334 //! destructeur. 00335 ~Triangle( ) {} 00336 00337 //! construit un triangle. 00338 Triangle( const int a, const int b, const int c ) 00339 { 00340 m_indices[0] = a; 00341 m_indices[1] = b; 00342 m_indices[2] = c; 00343 } 00344 00345 //! fixe l'identifiant de la matiere du triangle. 00346 void setMaterial( const int id ) 00347 { 00348 m_material_id = id; 00349 } 00350 00351 //! fixe le smooth group du triangle 00352 void setSmoothGroup( const int group_id ) 00353 { 00354 m_smooth_id = group_id; 00355 } 00356 00357 //! renvoie l'indice du sommet a du triangle. 00358 int a( ) const 00359 { 00360 return m_indices[0]; 00361 } 00362 00363 //! renvoie l'indice du sommet b du triangle. 00364 int b( ) const 00365 { 00366 return m_indices[1]; 00367 } 00368 00369 //! renvoie l'indice du sommet c du triangle. 00370 int c( ) const 00371 { 00372 return m_indices[2]; 00373 } 00374 00375 //! renvoie l'identifiant de la matiere du triangle. 00376 int material( ) const 00377 { 00378 return m_material_id; 00379 } 00380 00381 //! renvoie l'identifiant du smooth group du triangle. 00382 int smoothGroup( ) const 00383 { 00384 return m_smooth_id; 00385 } 00386 00387 //! comparaison de 2 sommets pour l'insertion dans une std::map 00388 static 00389 bool material_less( const Triangle& a, const Triangle& b ) 00390 { 00391 return ( a.material() < b.material() ); 00392 } 00393 }; 00394 00395 } // namespace OBJ 00396 #endif 00397 00398 } 00399 00400 #endif