34#ifndef AIMS_IO_WAVEFRONTMESHR_H
35#define AIMS_IO_WAVEFRONTMESHR_H
42#include <cartodata/volume/volume.h>
43#include <cartobase/exception/file.h>
44#include <cartobase/exception/format.h>
45#include <cartobase/stream/fileutil.h>
53#include <cartobase/exception/ioexcept.h>
63 inline static void r( std::istream & s, T & tex )
70 template <
typename T,
int D>
75 void r( std::istream & s, AimsVector<T, D> & tex )
78 for( i=0; i<3 && i<D; ++i )
92 template<
long D,
typename T>
100 const carto::AllocatorContext & context,
105 const std::vector<Point3df> & vertices,
106 const std::vector<Point3df> &normals,
108 const std::vector<T> & texture,
109 const std::vector<int> & normals_ind,
110 const std::vector<int> & texture_ind,
int timestep );
114 void setMtl(
carto::Object mtl_dict,
const std::string & mtl_objname,
121 template <
long D,
typename T>
122 inline WavefrontMeshReader<D,T> &
126 reader.
read( thing, thing.allocator(),
132 template <
long D,
typename T>
135 std::string & mtl_filename )
139 std::ifstream ms( mtl_filename.c_str() );
142 std::cerr <<
"warning: could not open " << mtl_filename << std::endl;
146 ms.setf( std::ios::skipws );
147 soma::IStreamDataSource ds( ms );
149 carto::Object current_obj;
150 carto::Object current_mat;
151 std::string l, element, objname;
154 while( ds && !ds.eof() )
162 std::cerr <<
"warning: could read " << mtl_filename <<
", line "
163 << line + 1 << std::endl;
169 if( l.empty() || l[0] ==
'#' )
172 std::stringstream s( l );
175 if( element ==
"newmtl" )
177 objname = l.substr( s.tellg(), l.length() - s.tellg() );
179 while( !objname.empty() && objname[i] ==
' ' )
181 objname = objname.substr( i, objname.length() - i );
184 mtl_dict->setProperty( objname, current_obj );
186 current_obj->setProperty(
"material", current_mat );
188 else if( element ==
"Ka" )
192 std::cerr <<
"MTL error: no current object.\n";
195 std::vector<float> ambient( 3 );
196 s >> ambient[0] >> ambient[1] >> ambient[2];
197 current_mat->setProperty(
"ambient", ambient );
199 else if( element ==
"Ke" )
203 std::cerr <<
"MTL error: no current object.\n";
206 std::vector<float> emission( 3 );
207 s >> emission[0] >> emission[1] >> emission[2];
208 current_mat->setProperty(
"emission", emission );
210 else if( element ==
"Kd" )
214 std::cerr <<
"MTL error: no current object.\n";
217 std::vector<float> diffuse( 4, 1. );
218 if( current_mat->getProperty(
"diffuse", diffuse ) )
219 while( diffuse.size() < 4 )
220 diffuse.push_back( 1. );
221 s >> diffuse[0] >> diffuse[1] >> diffuse[2];
222 current_mat->setProperty(
"diffuse", diffuse );
224 else if( element ==
"Ks" )
228 std::cerr <<
"MTL error: no current object.\n";
231 std::vector<float> specular( 3 );
232 s >> specular[0] >> specular[1] >> specular[2];
233 current_mat->setProperty(
"specular", specular );
235 else if( element ==
"Ns" )
239 std::cerr <<
"MTL error: no current object.\n";
244 current_mat->setProperty(
"shininess", ns );
246 else if( element ==
"d" )
250 std::cerr <<
"MTL error: no current object.\n";
255 std::vector<float> diffuse( 4, 0.8 );
256 if( current_mat->getProperty(
"diffuse", diffuse ) )
257 while( diffuse.size() < 4 )
258 diffuse.push_back( 0.8 );
260 current_mat->setProperty(
"diffuse", diffuse );
262 else if( element ==
"Tr" )
266 std::cerr <<
"MTL error: no current object.\n";
271 std::vector<float> diffuse( 4, 0.8 );
272 if( current_mat->getProperty(
"diffuse", diffuse ) )
273 while( diffuse.size() < 4 )
274 diffuse.push_back( 0.8 );
275 diffuse[3] = 1.f - a;
276 current_mat->setProperty(
"diffuse", diffuse );
278 else if( element ==
"map_Kd" )
282 std::cerr <<
"MTL error: no current object.\n";
287 bool image_found =
false;
288 while( !image_found && s )
294 std::vector<float> tex_offset( 3 );
295 s >> tex_offset[0] >> tex_offset[1] >> tex_offset[2];
296 current_obj->setProperty(
"texture_offset", tex_offset );
298 else if( item ==
"-s" )
301 std::vector<float> tex_scale( 3 );
302 s >> tex_scale[0] >> tex_scale[1] >> tex_scale[2];
303 current_obj->setProperty(
"texture_scale", tex_scale );
305 else if( item ==
"-clamp" )
311 std::string teximage_fname
317 carto::rc_ptr<carto::Volume<AimsRGBA> > teximage( r.read() );
318 std::map<int, carto::Object> palettes;
319 mtl_dict->getProperty(
"_texture_palettes", palettes );
321 mtl_dict->setProperty(
"_texture_palettes", palettes );
325 std::cout <<
"failed to read texture image " << teximage_fname
331 else if( element ==
"illum" )
335 std::cerr <<
"MTL error: no current object.\n";
340 current_obj->setProperty(
"illum", illum );
343 else if( element ==
"Ni" )
347 std::cerr <<
"MTL error: no current object.\n";
352 current_obj->setProperty(
"optical_density", ni );
357 std::cout <<
"unrecognized MTL tag: " << element << std::endl;
365 template <
long D,
typename T>
367 void WavefrontMeshReader<D,T>::setMtl( carto::Object mtl_dict,
368 const std::string & mtl_objname,
371 carto::Object m = mtl_dict->getProperty( mtl_objname );
377 mat = m->getProperty(
"material" );
378 carto::Object minfmat = hdr.getProperty(
"material" );
379 mat->copyProperties( minfmat );
385 hdr.copyProperties( m );
387 hdr.setProperty(
"material", mat );
389 if( mtl_dict->hasProperty(
"_texture_palettes" ) )
391 carto::Object palettes = mtl_dict->getProperty(
"_texture_palettes" );
392 hdr.setProperty(
"_texture_palettes", palettes );
397 template <
long D,
typename T>
399 void WavefrontMeshReader<D,T>::storeMesh(
400 AimsTimeSurface<D,T>& thing,
401 const std::vector<Point3df> & vertices,
402 const std::vector<Point3df> &normals,
403 const std::vector<AimsVector<uint, D> > & polygons,
404 const std::vector<T> & texture,
405 const std::vector<int> & normals_ind,
406 const std::vector<int> & texture_ind,
int timestep )
408 thing[timestep].
vertex() = vertices;
409 std::vector<Point3df> o_normals;
410 if( normals_ind.size() != normals.size() )
414 o_normals.resize( normals_ind.size() );
416 for(
int i=0, k=normals_ind.size(); i<k; ++i )
418 if( normals_ind[i] < 0 || normals_ind[i] >=
static_cast<int>(vertices.size()) )
421 s <<
"normal index out of range: " << normals_ind[i] <<
" / "
422 << vertices.size() <<
" at index " << i;
423 throw carto::parse_error( s.str() ,
"", _name, i );
425 o_normals[i] = normals[normals_ind[i]];
428 thing[timestep].
normal() = o_normals;
429 thing[timestep].
polygon() = polygons;
435 std::vector<T> o_texture;
436 o_texture.resize( texture_ind.size() );
437 for(
int i=0, k=texture_ind.size(); i<k; ++i )
439 if( texture_ind[i] < 0
440 || texture_ind[i] >=
static_cast<int>(texture.size()) )
443 if( texture_ind[i] >= 0 )
445 s <<
"texture index out of range: " << texture_ind[i] <<
" / "
446 << texture.size() <<
" at index " << i;
447 throw carto::parse_error( s.str(),
"", _name, i );
450 o_texture[i] = texture[0];
453 o_texture[i] = texture[texture_ind[i]];
455 thing[timestep].
texture() = o_texture;
460 template <
long D,
typename T>
463 const carto::AllocatorContext & ,
466 std::string filename = _name;
470 std::ifstream istr( filename.c_str(), std::ios::in );
471 istr.unsetf( std::ios::skipws );
473 soma::io_error::launchErrnoExcept( filename );
475 istr.setf( std::ios::skipws );
481 std::vector<Point3df> vertices, normals;
482 std::vector<AimsVector<uint, D> > polygons;
483 std::vector<T> texture;
484 std::vector<int> normals_ind;
485 std::vector<int> texture_ind;
487 bool update_normals =
false;
490 while( ds && !ds.
eof() )
497 throw soma::wrong_format_error( filename );
505 std::stringstream s(l);
511 if( timestep != 0 || !vertices.empty() )
513 storeMesh( thing, vertices, normals, polygons, texture, normals_ind,
514 texture_ind, timestep );
516 if( thing[timestep].normal().size() != vertices.size() )
517 update_normals =
true;
527 else if( element ==
"g" )
529 else if( element ==
"s" )
531 else if( element ==
"mtllib" )
533 std::string mtl_filename;
534 mtl_filename = l.substr( s.tellg(), l.length() - s.tellg() );
536 while( !mtl_filename.empty() && mtl_filename[i] ==
' ' )
538 mtl_filename = mtl_filename.substr( i, mtl_filename.length() - i );
541 mtl_dict = readMtlFle( mtl_filename );
543 else if( element ==
"usemtl" )
545 std::string mtl_objname;
546 mtl_objname = l.substr( s.tellg(), l.length() - s.tellg() );
548 while( !mtl_objname.empty() && mtl_objname[i] ==
' ' )
550 mtl_objname = mtl_objname.substr( i, mtl_objname.length() - i );
551 setMtl( mtl_dict, mtl_objname, hdr );
553 else if( element ==
"v" )
557 s >> p[0] >> p[1] >> p[2];
558 vertices.push_back(p);
560 else if( element ==
"vn" )
564 s >> p[0] >> p[1] >> p[2];
565 normals.push_back(p);
567 else if( element ==
"vt" )
571 _readTexture<T>::r( s, tex );
572 texture.push_back(tex);
574 else if( element ==
"f" || (D == 2 && element ==
"l" ) )
578 std::string::size_type pos, pos0;
583 for(
int p=0; p<D; ++p )
586 pos0 = item.find(
'/' );
587 std::stringstream z( item.substr(0, pos0 ) );
590 poly[p] = vertices.size() + pol;
593 if( pos0 == std::string::npos )
597 pos = item.find(
'/', pos0 );
601 std::stringstream z( item.substr(pos0, pos - pos0 ) );
603 if( texture_ind.size() <= poly[p] )
604 texture_ind.resize( poly[p] + 1, -1 );
605 if( texture_ind[ poly[p] ] < 0 )
606 texture_ind[ poly[p] ] = tex - 1;
607 else if( texture_ind[ poly[p] ] != tex - 1 )
611 vertices.push_back( vertices[ poly[p] ] );
612 poly[p] = vertices.size() - 1;
613 texture_ind.resize( poly[p] + 1, -1 );
614 texture_ind[ poly[p] ] = tex - 1;
617 else if( pos != pos0 )
619 if( pos == std::string::npos )
622 std::stringstream n( item.substr( pos0, item.length() - pos0 ) );
626 if( normals_ind.size() <= poly[p] )
627 normals_ind.resize( poly[p] + 1 );
628 normals_ind[ poly[p] ] =
norm - 1;
630 polygons.push_back( poly );
634 std::cerr <<
"unrecognized element: " << element <<
", " << D <<
", " << l << std::endl;
643 storeMesh( thing, vertices, normals, polygons, texture, normals_ind,
644 texture_ind, timestep );
646 if( update_normals || thing[timestep].normal().size() != vertices.size() )
The template class to manage a mesh with time if needed.
void erase()
Clear all the meshes.
void setHeader(const aims::PythonHeader &hdr)
Set the header.
const std::vector< Point3df > & normal() const
Get a const reference to the vector of normals of the 0 surface.
const std::vector< AimsVector< uint, D > > & polygon() const
Get a const reference to the vector of polygons of the 0 surface.
const std::vector< T > & texture() const
Get a const reference to the vector of textures of the 0 surface.
void updateNormals()
Update/Compute the normals.
const std::vector< Point3df > & vertex() const
Get a const reference to the vector of verteces of the surface of index 0.
Generic reader for every format of Aims object.
void read(AimsTimeSurface< D, T > &thing, const carto::AllocatorContext &context, carto::Object options)
WavefrontMeshReader(const std::string &name)
static std::string dirname(const std::string &)
Object value(const Object &value)
virtual bool removeProperty(const std::string &)
virtual bool hasProperty(const std::string &) const
static bool getline(DataSource &ds, std::string &)
The class for EcatSino data write operation.
GenesisReader< T > & operator>>(GenesisReader< T > &reader, AimsData< T > &thing)
std::map< std::string, Object > Dictionary
AimsVector< float, 3 > Point3df
float norm(const AimsVector< T, D > &v1)