Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

objreader.C

Go to the documentation of this file.
00001 /*!
00002  *  \file objreader.C
00003  *  \brief Contains the implementation of the OBJReader class.
00004  *
00005  *  \sa objreader.H
00006  *
00007  */
00008 
00009 #include <iostream>
00010 #include <fstream>
00011 #include <sstream>
00012 #include <vector>
00013 #include <map>
00014 #include <string>
00015 #include <limits>
00016 #include <algorithm>
00017 
00018 using namespace std;
00019 
00020 #include "geom/texturegl.H"
00021 #include "mesh/bmesh.H"
00022 #include "mesh/patch.H"
00023 #include "mlib/points.H"
00024 #include "std/config.H"
00025 
00026 using namespace mlib;
00027 
00028 #include "objreader.H"
00029 
00030 static bool debug = Config::get_var_bool("DEBUG_OBJ_READER",false);
00031 
00032 /*!
00033  *  \brief Ignore all the characters in stream \p in until the character \p delim
00034  *  is encountered.  By default this ignores all characters until the next
00035  *  new-line is encountered, effectively "eating" the rest of the line.
00036  *
00037  */
00038 inline void
00039 eat_line(istream& in, int delim = '\n')
00040 {
00041    in.ignore(numeric_limits<std::streamsize>::max(), delim);
00042 }
00043 
00044 //----------------------------------------------------------------------------//
00045 
00046 /*!
00047  *  \brief A semi-generic parser class for reading files formatted similiarly to
00048  *  .obj and .mtl files.
00049  *
00050  *  A parser class that reads files that are formatted such that each line starts
00051  *  with an identifying token that is followed by data.  Blank lines, comments
00052  *  starting with the '#' character, and line continuations with the '\' character
00053  *  are also allowed.
00054  *
00055  *  Exactly what actions are performed for each token are customizable using
00056  *  registered callback functions.
00057  *
00058  *  The class is templated on a type which is passed as an additional parameter
00059  *  to each callback function.  Typically, this type will be the type of a class
00060  *  which has all of the callback functions as static members.
00061  *
00062  */
00063 template <typename T>
00064 class Reader {
00065    
00066  public:
00067       
00068    Reader()
00069       : read_succeeded(false)
00070       { }
00071       
00072    bool read(istream &in, T *object);
00073       
00074    void add_reader_function(const string &name,
00075                             bool (*func)(istream&, T*));
00076       
00077    bool was_successful() const
00078       { return read_succeeded; }
00079       
00080  private:
00081       
00082    bool read_succeeded;
00083       
00084    typedef map<string, bool (*)(istream&, T*)> reader_map_t;
00085    reader_map_t reader_map;
00086       
00087    //! \name Parsing Functions
00088    //@{
00089       
00090    string get_next_token(istream &in);
00091       
00092    void ignore_element(istream &in);
00093       
00094    void extract_line(istream &in, string &line);
00095       
00096    //@}
00097    
00098 };
00099 
00100 template <typename T>
00101 bool
00102 Reader<T>::read(istream &in, T *object)
00103 {
00104    
00105    // Reset reader state:
00106    
00107    read_succeeded = true;
00108    
00109    // Read stream:
00110    
00111    string token;
00112    string line;
00113    
00114    typename reader_map_t::iterator reader_itor;
00115    
00116    while(read_succeeded && !(token = get_next_token(in)).empty()){
00117       
00118       reader_itor = reader_map.find(token);
00119       
00120       if(reader_itor == reader_map.end()){
00121          
00122          // Skip the element for this token if we don't know how to read it:
00123          ignore_element(in);
00124          
00125          cerr << "Reader::read() - Warning:  Skipped element with token "
00126               << token << endl;
00127          
00128       } else {
00129          
00130          extract_line(in, line);
00131          
00132          istringstream line_stream(line);
00133          
00134          read_succeeded = read_succeeded &&
00135             (*(reader_itor->second))(line_stream, object);
00136          
00137       }
00138       
00139    }
00140    
00141    if(!read_succeeded){
00142       
00143       cerr << "Reader::read() - Error:  Failed while reading element with token "
00144            << token << endl;
00145       
00146    }
00147    
00148    return read_succeeded;
00149    
00150 }
00151 
00152 template <typename T>
00153 void
00154 Reader<T>::add_reader_function(const string &name,
00155                                bool (*func)(istream&, T*))
00156 {
00157    
00158    reader_map[name] = func;
00159    
00160 }
00161 
00162 /*!
00163  *  \brief Skips over comments until it finds a whitespace delimited token.
00164  *  \return The token if one is found.  Otherwise the empty string.
00165  *
00166  */
00167 template <typename T>
00168 string
00169 Reader<T>::get_next_token(istream &in)
00170 {
00171    
00172    string buf;
00173    
00174    // Get the next whitespace delimited token:
00175    while(in >> buf){
00176       
00177       // See if the token is actually the beginning of a comment:
00178       if(buf[0] == '#')
00179          eat_line(in);  // Discard the rest of the line (it's a comment)
00180       else
00181          break;         // If we don't have a comment, we're done
00182       
00183    }
00184    
00185    // Return the empty string if the stream went bad before we found anything:
00186    return in ? buf : string();
00187    
00188 }
00189 
00190 /*!
00191  *  \brief Skips over the next element in the stream \p in including any comments
00192  *  and line continuations.
00193  *
00194  */
00195 template <typename T>
00196 void
00197 Reader<T>::ignore_element(istream &in)
00198 {
00199    
00200    char c;
00201    
00202    while(in.get(c)){
00203       
00204       if(c == '\\')
00205          eat_line(in);
00206       else if(c == '\n')
00207          break;
00208       
00209    }
00210    
00211 }
00212 
00213 /*!
00214  *  \brief Extracts an entire line from the stream \p in and puts it in the
00215  *  string \p line.  This function will collapse multiple lines into one if there
00216  *  are line continuations.
00217  *
00218  */
00219 template <typename T>
00220 void
00221 Reader<T>::extract_line(istream &in, string &line)
00222 {
00223    
00224    line.clear();
00225    
00226    string buf;
00227    
00228    string::size_type continuation_loc;
00229    
00230    while(getline(in, buf)){
00231       
00232       if((continuation_loc = buf.rfind('\\')) != string::npos){
00233          
00234          buf.resize(continuation_loc);
00235          
00236          line.push_back(' ');
00237          line.append(buf);
00238          
00239       } else {
00240          
00241          line.append(buf);         
00242          break;
00243          
00244       }
00245       
00246    }
00247    
00248 }
00249 
00250 //----------------------------------------------------------------------------//
00251 
00252 /*!
00253  *  \brief A class to represent a face in a .obj file.
00254  *
00255  */
00256 class OBJFace {
00257    
00258  public:
00259       
00260    OBJFace(long mtl_index_in = -1)
00261       : mtl_index(mtl_index_in)
00262       { }
00263       
00264    unsigned long num_vertices() const { return vertices.size(); }
00265    unsigned long num_texcoords() const { return texcoords.size(); }
00266    unsigned long num_normals() const { return normals.size(); }
00267       
00268    unsigned long get_vertex_idx(unsigned long idx) const
00269       { return vertices[idx]; }
00270    unsigned long get_texcoord_idx(unsigned long idx) const
00271       { return texcoords[idx]; }
00272    unsigned long get_normal_idx(unsigned long idx) const
00273       { return normals[idx]; }
00274       
00275    bool has_texcoords() const { return num_texcoords() > 0; }
00276    bool has_normals() const { return num_normals() > 0; }
00277       
00278    bool add_vertex(long vertex, unsigned long total_vertices);
00279    bool add_texcoord(long texcoord, unsigned long total_texcoords);
00280    bool add_normal(long normal, unsigned long total_normals);
00281       
00282    //! \brief Checks ot see if this face has consistent numbers of vertices,
00283    //! texture coordinates, and normals.
00284    bool good() const;
00285       
00286  private:
00287       
00288    bool process_index(long index, unsigned long max_val,
00289                       vector<unsigned long> &index_list);
00290       
00291    long mtl_index;
00292       
00293    vector<unsigned long> vertices;
00294    vector<unsigned long> texcoords;
00295    vector<unsigned long> normals;
00296    
00297 };
00298 
00299 bool
00300 OBJFace::add_vertex(long vertex, unsigned long total_vertices)
00301 {
00302    
00303    return process_index(vertex, total_vertices, vertices);
00304    
00305 }
00306 
00307 bool
00308 OBJFace::add_texcoord(long texcoord, unsigned long total_texcoords)
00309 {
00310    
00311    return process_index(texcoord, total_texcoords, texcoords);
00312    
00313 }
00314 
00315 bool
00316 OBJFace::add_normal(long normal, unsigned long total_normals)
00317 {
00318    
00319    return process_index(normal, total_normals, normals);
00320    
00321 }
00322 
00323 bool
00324 OBJFace::good() const
00325 {
00326    
00327    return ((vertices.size() > 2) &&
00328            ((vertices.size() == texcoords.size()) || texcoords.empty()) &&
00329            ((vertices.size() == normals.size())   || normals.empty()));
00330    
00331 }
00332 
00333 /*!
00334  *  \brief Process a vertex position, texture coordinate or normal index to see
00335  *  if it is valid and, if so, to normalize it and add it to the given vector.
00336  *
00337  *  \param[in] index The index to check and add (if the check succeeds).
00338  *  \param[in] max_val The maximum value that the index can take (this should
00339  *  be equal to the number of elements (vertices, texture coordinates, or normals)
00340  *  that have been read in the .obj file at the time this face is read.
00341  *  \param[in,out] index_list The vector of indices to add the vertex to if it
00342  *  is valid.
00343  *
00344  *  \return \c true if the index is valid and \c false otherwise.
00345  *
00346  */
00347 bool
00348 OBJFace::process_index(long index, unsigned long max_val,
00349                        vector<unsigned long> &index_list)
00350 {
00351    
00352    // Check for invalid cases:
00353    if((index == 0) ||
00354       (index > static_cast<long>(max_val)) ||
00355       (index < -static_cast<long>(max_val))){
00356          
00357       return false;
00358       
00359    }
00360       
00361    if(index < 0)
00362       index = max_val + index + 1;
00363    
00364    index_list.push_back(static_cast<unsigned long>(index));
00365    
00366    return true;
00367    
00368 }
00369 
00370 //----------------------------------------------------------------------------//
00371 
00372 /*!
00373  *  \brief A class to represent a material in a .obj file.
00374  *
00375  */
00376 class OBJMtl {
00377    
00378  public:
00379       
00380    enum color_component_t {COLOR_RED = 0, COLOR_GREEN = 1, COLOR_BLUE = 2};
00381       
00382    OBJMtl(const string &mtl_name = "",
00383           double ambt_r = 0.2, double ambt_g = 0.2, double ambt_b = 0.2,
00384           double diff_r = 0.8, double diff_g = 0.8, double diff_b = 0.8,
00385           double spec_r = 1.0, double spec_g = 1.0, double spec_b = 1.0,
00386           double trans = 1.0, double shin = 0.0, int illum = 1,
00387           const string &texture_color_diffuse_filename = "");
00388       
00389    const string &get_name() const
00390       { return name; }
00391       
00392    double get_ambient(color_component_t comp) const
00393       { return color_ambient[comp]; }
00394       
00395    void set_ambient(color_component_t comp, double val)
00396       { color_ambient[comp] = val; }
00397       
00398    void set_ambient(double ambient[3])
00399       { copy(ambient, ambient + 3, color_ambient); }
00400       
00401    double get_diffuse(color_component_t comp) const
00402       { return color_diffuse[comp]; }
00403       
00404    void set_diffuse(color_component_t comp, double val)
00405       { color_diffuse[comp] = val; }
00406       
00407    void set_diffuse(double diffuse[3])
00408       { copy(diffuse, diffuse + 3, color_diffuse); }
00409       
00410    double get_specular(color_component_t comp) const
00411       { return color_specular[comp]; }
00412       
00413    void set_specular(color_component_t comp, double val)
00414       { color_specular[comp] = val; }
00415       
00416    void set_specular(double specular[3])
00417       { copy(specular, specular + 3, color_specular); }
00418       
00419    double get_transparency() const
00420       { return transparency; }
00421       
00422    void set_transparency(double trans)
00423       { transparency = trans; }
00424       
00425    double get_shininess() const
00426       { return shininess; }
00427       
00428    void set_shininess(double shin)
00429       { shininess = shin; }
00430       
00431    int get_illumination_model() const
00432       { return illumination_model; }
00433       
00434    void set_illumination_model(int illum)
00435       { illumination_model = illum; }
00436       
00437    const string &get_diffuse_texture_map() const
00438       { return texmap_color_diffuse; }
00439       
00440    void set_diffuse_texture_map(const string &texmap)
00441       { texmap_color_diffuse = texmap; }
00442       
00443  private:
00444       
00445    string name;
00446       
00447    double color_ambient[3];
00448    double color_diffuse[3];
00449    double color_specular[3];
00450       
00451    double transparency;
00452       
00453    double shininess;
00454       
00455    int illumination_model;
00456       
00457    string texmap_color_diffuse;
00458    
00459 };
00460 
00461 OBJMtl::OBJMtl(const string &mtl_name,
00462                double ambt_r, double ambt_g, double ambt_b,
00463                double diff_r, double diff_g, double diff_b,
00464                double spec_r, double spec_g, double spec_b,
00465                double trans, double shin, int illum,
00466                const string &texture_color_diffuse_filename)
00467    : name(mtl_name), transparency(trans), shininess(shin),
00468      illumination_model(illum),
00469      texmap_color_diffuse(texture_color_diffuse_filename)
00470 {
00471    
00472    color_ambient[0] = ambt_r;
00473    color_ambient[1] = ambt_g;
00474    color_ambient[2] = ambt_b;
00475    
00476    color_diffuse[0] = diff_r;
00477    color_diffuse[1] = diff_g;
00478    color_diffuse[2] = diff_b;
00479    
00480    color_specular[0] = spec_r;
00481    color_specular[1] = spec_g;
00482    color_specular[2] = spec_b;
00483    
00484 }
00485 
00486 //----------------------------------------------------------------------------//
00487 
00488 /*!
00489  *  \brief A class that can read .mtl files and create OBJMtl objects from them.
00490  *
00491  */
00492 class MTLReader {
00493    
00494  public:
00495       
00496    MTLReader();
00497       
00498    bool read(istream &in);
00499       
00500    bool has_material(const string &mtl_name) const
00501       { return mtl_name2id.count(mtl_name) > 0; }
00502       
00503    const OBJMtl &get_material(const string &mtl_name) const
00504       { assert(has_material(mtl_name));
00505       return materials[mtl_name2id.find(mtl_name)->second]; }
00506       
00507  private:
00508       
00509    Reader<MTLReader> reader;
00510       
00511    //! \name Element Reading Functions
00512    //@{
00513       
00514    static bool read_newmtl(istream &in, MTLReader *self);
00515    static bool read_Ka(istream &in, MTLReader *self);
00516    static bool read_Kd(istream &in, MTLReader *self);
00517    static bool read_Ks(istream &in, MTLReader *self);
00518    static bool read_d(istream &in, MTLReader *self);
00519    static bool read_Tr(istream &in, MTLReader *self);
00520    static bool read_Ns(istream &in, MTLReader *self);
00521    static bool read_illum(istream &in, MTLReader *self);
00522    static bool read_map_Kd(istream &in, MTLReader *self);
00523       
00524    bool exists_current_material();
00525       
00526    //@}
00527       
00528    //! \name Reader State
00529    //@{
00530       
00531    vector<OBJMtl> materials;
00532       
00533    typedef map<string, long> mtl_name2id_map_t;
00534    mtl_name2id_map_t mtl_name2id;
00535       
00536    //@}
00537    
00538 };
00539 
00540 MTLReader::MTLReader()
00541 {
00542    
00543    reader.add_reader_function("newmtl", &MTLReader::read_newmtl);
00544    reader.add_reader_function("Ka", &MTLReader::read_Ka);
00545    reader.add_reader_function("Kd", &MTLReader::read_Kd);
00546    reader.add_reader_function("Ks", &MTLReader::read_Ks);
00547    reader.add_reader_function("d", &MTLReader::read_d);
00548    reader.add_reader_function("Tr", &MTLReader::read_Tr);
00549    reader.add_reader_function("Ns", &MTLReader::read_Ns);
00550    reader.add_reader_function("illum", &MTLReader::read_illum);
00551    reader.add_reader_function("map_Kd", &MTLReader::read_map_Kd);
00552    
00553 }
00554 
00555 bool
00556 MTLReader::read(istream &in)
00557 {
00558    
00559    // Clear reader state:
00560    
00561    materials.clear();
00562    mtl_name2id.clear();
00563    
00564    return reader.read(in, this);
00565    
00566 }
00567 
00568 bool
00569 MTLReader::read_newmtl(istream &in, MTLReader *self)
00570 {
00571    
00572    string name;
00573    
00574    if(!(in >> name))
00575       return false;
00576    
00577    // Make sure that the new material name hasn't been used before:
00578    if(self->mtl_name2id.count(name) != 0)
00579       return false;
00580    
00581    self->materials.push_back(OBJMtl(name));
00582    
00583    self->mtl_name2id[name] = self->materials.size() - 1;
00584    
00585    return true;
00586    
00587 }
00588 
00589 bool
00590 MTLReader::read_Ka(istream &in, MTLReader *self)
00591 {
00592    
00593    if(!self->exists_current_material())
00594       return false;
00595    
00596    double ambient[3];
00597    
00598    if(!(in >> ambient[0] >> ambient[1] >> ambient[2]))
00599       return false;
00600    
00601    self->materials.back().set_ambient(ambient);
00602    
00603    return true;
00604    
00605 }
00606 
00607 bool
00608 MTLReader::read_Kd(istream &in, MTLReader *self)
00609 {
00610    
00611    if(!self->exists_current_material())
00612       return false;
00613    
00614    double diffuse[3];
00615    
00616    if(!(in >> diffuse[0] >> diffuse[1] >> diffuse[2]))
00617       return false;
00618    
00619    self->materials.back().set_diffuse(diffuse);
00620    
00621    return true;
00622    
00623 }
00624 
00625 bool
00626 MTLReader::read_Ks(istream &in, MTLReader *self)
00627 {
00628    
00629    if(!self->exists_current_material())
00630       return false;
00631    
00632    double specular[3];
00633    
00634    if(!(in >> specular[0] >> specular[1] >> specular[2]))
00635       return false;
00636    
00637    self->materials.back().set_specular(specular);
00638    
00639    return true;
00640    
00641 }
00642 
00643 bool
00644 MTLReader::read_d(istream &in, MTLReader *self)
00645 {
00646    
00647    return read_Tr(in, self);
00648    
00649 }
00650 
00651 bool
00652 MTLReader::read_Tr(istream &in, MTLReader *self)
00653 {
00654    
00655    if(!self->exists_current_material())
00656       return false;
00657    
00658    double trans;
00659    
00660    if(!(in >> trans))
00661       return false;
00662    
00663    self->materials.back().set_transparency(trans);
00664    
00665    return true;
00666    
00667 }
00668 
00669 bool
00670 MTLReader::read_Ns(istream &in, MTLReader *self)
00671 {
00672    
00673    if(!self->exists_current_material())
00674       return false;
00675    
00676    double shin;
00677    
00678    if(!(in >> shin))
00679       return false;
00680    
00681    self->materials.back().set_shininess(shin);
00682    
00683    return true;
00684    
00685 }
00686 
00687 bool
00688 MTLReader::read_illum(istream &in, MTLReader *self)
00689 {
00690    
00691    if(!self->exists_current_material())
00692       return false;
00693    
00694    int illum;
00695    
00696    if(!(in >> illum))
00697       return false;
00698    
00699    self->materials.back().set_illumination_model(illum);
00700    
00701    return true;
00702    
00703 }
00704 
00705 bool
00706 MTLReader::read_map_Kd(istream &in, MTLReader *self)
00707 {
00708    
00709    if(!self->exists_current_material())
00710       return false;
00711    
00712    string texmap;
00713    
00714    if(!(in >> texmap))
00715       return false;
00716    
00717    self->materials.back().set_diffuse_texture_map(texmap);
00718    
00719    return true;
00720    
00721 }
00722 
00723 bool
00724 MTLReader::exists_current_material()
00725 {
00726    
00727    return materials.size() > 0;
00728    
00729 }
00730 
00731 //----------------------------------------------------------------------------//
00732 
00733 /*!
00734  *  \brief The implementation of the OBJReader class.
00735  *
00736  */
00737 class OBJReaderImpl {
00738 
00739  public:
00740       
00741    OBJReaderImpl();
00742       
00743    bool read(istream &in);
00744       
00745    BMESH *get_mesh() const;
00746       
00747    void get_mesh(BMESH *mesh) const;
00748       
00749    friend class OBJReader;
00750       
00751  private:
00752       
00753    Reader<OBJReaderImpl> reader;
00754       
00755    bool read_mtl_files();
00756       
00757    //! \name Element Reading Functions
00758    //@{
00759       
00760    static bool read_v(istream &in, OBJReaderImpl *self);
00761    static bool read_vn(istream &in, OBJReaderImpl *self);
00762    static bool read_vt(istream &in, OBJReaderImpl *self);
00763    static bool read_f(istream &in, OBJReaderImpl *self);
00764    static bool read_mtllib(istream &in, OBJReaderImpl *self);
00765    static bool read_usemtl(istream &in, OBJReaderImpl *self);
00766       
00767    //@}
00768       
00769    //! \name Reader State
00770    //@{
00771       
00772    bool read_succeeded;
00773       
00774    vector<Wpt> vertices;
00775    vector<Wvec> normals;
00776    vector<UVpt> texcoords;
00777    vector<OBJFace> faces;
00778       
00779    vector<string> mtl_files;
00780    vector<OBJMtl> materials;
00781    vector< vector<long> > material_faces;
00782       
00783    typedef map<string, long> mtl_name2id_map_t;
00784    mtl_name2id_map_t mtl_name2id;
00785       
00786    long current_material;
00787       
00788    //@}
00789       
00790    //! \name Mesh Building Functions
00791    //@{
00792       
00793    void add_vertices(BMESH *mesh) const;
00794       
00795    void add_patches(BMESH *mesh) const;
00796 
00797    void set_vert_normals(BMESH *mesh) const;
00798       
00799    void add_face(BMESH *mesh, Patch *patch, unsigned long index) const;
00800       
00801    void add_tri(BMESH *mesh, Patch *patch, const OBJFace &face,
00802                 unsigned long idx0, unsigned long idx1, unsigned long idx2) const;
00803       
00804    void add_creases(BMESH *mesh) const;
00805       
00806    //@}
00807       
00808    //! \name Mesh Building State:
00809    //@{
00810       
00811    //! Lookup .obj face index from mesh face index:
00812    mutable vector<unsigned long> mesh_faces2obj_faces;
00813       
00814    //@}
00815 
00816 };
00817 
00818 OBJReaderImpl::OBJReaderImpl()
00819    : read_succeeded(false), current_material(-1)
00820 {
00821    
00822    // Initialize reader functions pointers:
00823    
00824    reader.add_reader_function("v", &OBJReaderImpl::read_v);
00825    reader.add_reader_function("vn", &OBJReaderImpl::read_vn);
00826    reader.add_reader_function("vt", &OBJReaderImpl::read_vt);
00827    reader.add_reader_function("f", &OBJReaderImpl::read_f);
00828    reader.add_reader_function("mtllib", &OBJReaderImpl::read_mtllib);
00829    reader.add_reader_function("usemtl", &OBJReaderImpl::read_usemtl);
00830    
00831 }
00832 
00833 bool
00834 OBJReaderImpl::read(istream &in)
00835 {
00836    
00837    // Reset reader state:
00838    
00839    read_succeeded = false;
00840    
00841    vertices.clear();
00842    normals.clear();
00843    texcoords.clear();
00844    faces.clear();
00845    mtl_files.clear();
00846    materials.clear();
00847    mtl_name2id.clear();
00848    
00849    // Create default material (note that it is not in the name to id map because
00850    // the default material cannot be referenced by name):
00851    materials.push_back(OBJMtl());
00852    material_faces.push_back(vector<long>());
00853    current_material = 0;
00854    
00855    read_succeeded = reader.read(in, this);
00856    
00857    // Make sure we have a face list for each material:
00858    assert(materials.size() == material_faces.size());
00859    
00860    read_succeeded = read_succeeded && read_mtl_files();
00861    
00862    return read_succeeded;
00863    
00864 }
00865       
00866 BMESH*
00867 OBJReaderImpl::get_mesh() const
00868 {
00869    
00870    if(!read_succeeded) return 0;
00871    
00872    BMESH *mesh = new BMESH;
00873    
00874    get_mesh(mesh);
00875    
00876    return mesh;
00877    
00878 }
00879 
00880 void
00881 OBJReaderImpl::get_mesh(BMESH *mesh) const
00882 {
00883    
00884    // Do nothing if the read didn't succeed:
00885    if(!read_succeeded)
00886       return;
00887    
00888    // Clear the mesh's current data:
00889    mesh->delete_elements();
00890    
00891    // Clear mesh builder state:
00892    mesh_faces2obj_faces.clear();
00893    
00894    // Fill the mesh with the new data:
00895    
00896    add_vertices(mesh);
00897    
00898    add_patches(mesh);
00899    
00900    add_creases(mesh);
00901 
00902    set_vert_normals(mesh);
00903 
00904    mesh->changed();
00905 }
00906 
00907 bool
00908 OBJReaderImpl::read_mtl_files()
00909 {
00910    
00911    if(!read_succeeded)
00912       return false;
00913    
00914    MTLReader mtl_reader;
00915    
00916    for(unsigned long i = 0; i < mtl_files.size(); ++i){
00917       
00918       ifstream mtl_stream(mtl_files[i].c_str());
00919       
00920       if(!mtl_stream.is_open()){
00921          
00922          cerr << "OBJReader::read_mtl_files() - Warning:  Couldn't open material file "
00923               << mtl_files[i] << "!" << endl;
00924          
00925          continue;
00926          
00927       }
00928       
00929       if(!mtl_reader.read(mtl_stream))
00930          return false;
00931       
00932       for(unsigned long j = 0; j < materials.size(); ++j){
00933          
00934          if(mtl_reader.has_material(materials[j].get_name())){
00935             
00936             materials[j] = mtl_reader.get_material(materials[j].get_name());
00937             
00938          }
00939          
00940       }
00941       
00942    }
00943    
00944    return true;
00945    
00946 }
00947 
00948 /*!
00949  *  \brief Reads the data for a vertex position element in a .obj file (not
00950  *  including the starting 'v' token).
00951  *
00952  */
00953 bool
00954 OBJReaderImpl::read_v(istream &in, OBJReaderImpl *self)
00955 {
00956    
00957    double vals[3];
00958    
00959    if(!(in >> vals[0] >> vals[1] >> vals[2]))
00960       return false;
00961    
00962    self->vertices.push_back(Wpt(vals[0], vals[1], vals[2]));
00963    
00964    return true;
00965    
00966 }
00967 
00968 /*!
00969  *  \brief Reads the data for a vertex normal element in a .obj file (not
00970  *  including the starting 'vn' token).
00971  *
00972  */
00973 bool
00974 OBJReaderImpl::read_vn(istream &in, OBJReaderImpl *self)
00975 {
00976    
00977    double vals[3];
00978    
00979    if(!(in >> vals[0] >> vals[1] >> vals[2]))
00980       return false;
00981    
00982    self->normals.push_back(Wvec(vals[0], vals[1], vals[2]));
00983    
00984    return true;
00985    
00986 }
00987 
00988 /*!
00989  *  \brief Reads the data for a vertex texture coordinate element in a .obj file
00990  *  (not including the starting 'vt' token).
00991  *
00992  */
00993 bool
00994 OBJReaderImpl::read_vt(istream &in, OBJReaderImpl *self)
00995 {
00996    
00997    double vals[2];
00998    
00999    if(!(in >> vals[0] >> vals[1]))
01000       return false;
01001    
01002    self->texcoords.push_back(UVpt(vals[0], vals[1]));
01003    
01004    return true;
01005    
01006 }
01007 
01008 /*!
01009  *  \brief Reads the data for a face element in a .obj file (not including the
01010  *  starting 'f' token).
01011  *
01012  */
01013 bool
01014 OBJReaderImpl::read_f(istream &in, OBJReaderImpl *self)
01015 {
01016    
01017    long pos, tcoord, norm;
01018    
01019    char slash;
01020    
01021    OBJFace face(self->current_material);
01022    
01023    while(in >> pos){
01024    
01025       face.add_vertex(pos, self->vertices.size());
01026       
01027       if(in.peek() == '/'){
01028          
01029          in >> slash;
01030          
01031          if(in.peek() != '/'){
01032             
01033             in >> tcoord;
01034             face.add_texcoord(tcoord, self->texcoords.size());
01035             
01036          }
01037             
01038          if(in.peek() == '/'){
01039             
01040             in >> slash >> norm;
01041             face.add_normal(norm, self->normals.size());
01042             
01043          }
01044          
01045       }
01046       
01047    }
01048    
01049    if(!face.good())
01050       return false;
01051    
01052    self->faces.push_back(face);
01053    self->material_faces[self->current_material].push_back(self->faces.size() - 1);
01054    
01055    return true;
01056    
01057 }
01058 
01059 /*!
01060  *  \brief Reads the data for a material library element in a .obj file (not
01061  *  including the starting 'mtllib' token).
01062  *
01063  */
01064 bool
01065 OBJReaderImpl::read_mtllib(istream &in, OBJReaderImpl *self)
01066 {
01067    
01068    string buf;
01069    
01070    bool valid = false;
01071    
01072    while(in >> buf){
01073       
01074       if(buf[0] == '#')
01075          break; // Break out if we hit a comment
01076       
01077       self->mtl_files.push_back(buf);
01078       
01079       valid = true;
01080       
01081    }
01082    
01083    return valid;
01084    
01085 }
01086 
01087 /*!
01088  *  \brief Reads the data for a "use material" directive in a .obj file (not
01089  *  including the starting 'usemtl' token).
01090  *
01091  */
01092 bool
01093 OBJReaderImpl::read_usemtl(istream &in, OBJReaderImpl *self)
01094 {
01095    
01096    string mtl_name;
01097    
01098    // Fail on failed extraction or if a comment is extracted:
01099    if(!(in >> mtl_name) || (mtl_name[0] == '#'))
01100       return false;
01101    
01102    mtl_name2id_map_t::iterator name2id_itor = self->mtl_name2id.find(mtl_name);
01103    
01104    // See if this is the first time this material has been used:
01105    if(name2id_itor == self->mtl_name2id.end()){
01106       
01107       self->materials.push_back(OBJMtl(mtl_name));
01108       self->material_faces.push_back(vector<long>());
01109       
01110       name2id_itor =
01111          self->mtl_name2id.insert(self->mtl_name2id.begin(),
01112                                   make_pair(mtl_name, self->materials.size() - 1));
01113       
01114    }
01115    
01116    self->current_material = name2id_itor->second;
01117    
01118    return true;
01119    
01120 }
01121 
01122 void
01123 OBJReaderImpl::add_vertices(BMESH *mesh) const
01124 {
01125    
01126    for(unsigned long i = 0; i < vertices.size(); ++i){
01127       
01128       mesh->add_vertex(vertices[i]);
01129       
01130    }
01131    
01132 }
01133       
01134 void
01135 OBJReaderImpl::add_patches(BMESH *mesh) const
01136 {
01137    err_adv(debug, "OBJReaderImpl::add_patches: %d materials", int(materials.size()));
01138 
01139    for(unsigned long i = 0; i < materials.size(); ++i){
01140       
01141       if(material_faces[i].size() == 0)
01142          continue;
01143       
01144       Patch *patch = mesh->new_patch();
01145       
01146       if(materials[i].get_name().size() > 0)
01147          patch->set_name(materials[i].get_name().c_str());
01148 
01149       // the following is wrong when there are no materials...
01150       // haven't tracked down what part is wrong (materials come out
01151       // blinding bright) so just commenting it out now. --sapo 2/19/2006
01152 /*      
01153       patch->set_ambient_color(COLOR(materials[i].get_ambient(OBJMtl::COLOR_RED),
01154                                      materials[i].get_ambient(OBJMtl::COLOR_GREEN),
01155                                      materials[i].get_ambient(OBJMtl::COLOR_BLUE)));
01156       
01157       patch->set_color(COLOR(materials[i].get_diffuse(OBJMtl::COLOR_RED),
01158                              materials[i].get_diffuse(OBJMtl::COLOR_GREEN),
01159                              materials[i].get_diffuse(OBJMtl::COLOR_BLUE)));
01160       
01161       patch->set_specular_color(COLOR(materials[i].get_specular(OBJMtl::COLOR_RED),
01162                                       materials[i].get_specular(OBJMtl::COLOR_GREEN),
01163                                       materials[i].get_specular(OBJMtl::COLOR_BLUE)));
01164       
01165       patch->set_shininess(materials[i].get_shininess());
01166       
01167       patch->set_transp(materials[i].get_transparency());
01168       
01169       if(materials[i].get_diffuse_texture_map().size() > 0){
01170          
01171          patch->set_texture_file(materials[i].get_diffuse_texture_map().c_str());
01172          patch->set_texture(new TEXTUREgl(patch->texture_file()));
01173          
01174       }
01175 */      
01176       for(unsigned long j = 0; j < material_faces[i].size(); ++j)
01177          add_face(mesh, patch, material_faces[i][j]);
01178       
01179    }
01180 }
01181 
01182 void
01183 OBJReaderImpl::set_vert_normals(BMESH *mesh) const
01184 {
01185    assert(mesh);
01186    if (vertices.empty() || vertices.size() != normals.size()) {
01187       err_adv(debug, "OBJReaderImpl::set_vert_normals: skipping...");
01188       return;
01189    }
01190    err_adv(debug, "OBJReaderImpl::set_vert_normals: assigning normals to vertices");
01191    assert((unsigned long)(mesh->nverts()) == normals.size());
01192    for (unsigned long i=0; i<normals.size(); i++) {
01193       mesh->bv(int(i))->set_norm(normals[i]);
01194    }
01195 }
01196 
01197 void
01198 OBJReaderImpl::add_face(BMESH *mesh, Patch *patch, unsigned long index) const
01199 {
01200    
01201    assert(faces[index].good());
01202 
01203    for(unsigned long k = 2; k < faces[index].num_vertices(); ++k){
01204       
01205       add_tri(mesh, patch, faces[index], 0, k-1, k);
01206       mesh_faces2obj_faces.push_back(index);
01207       
01208    }
01209    
01210    // If the face is a quad, mark the quad diagonal as "weak":
01211    if (faces[index].num_vertices() == 4) {
01212       
01213       Bedge* e = lookup_edge(mesh->bv(faces[index].get_vertex_idx(0) - 1),
01214                              mesh->bv(faces[index].get_vertex_idx(2) - 1));
01215       assert(e);
01216       e->set_bit(Bedge::WEAK_BIT);
01217       
01218    }
01219    
01220 }
01221 
01222 /*!
01223  *  \brief Adds a triangle to BMESH \p mesh and Patch \p patch from the OBJFace
01224  *  \p face.  \p idx0, \p idx1 and \p idx2 are the indices (with respect to the
01225  *  face) of the three vertices that make up the triangle.
01226  *
01227  */
01228 void
01229 OBJReaderImpl::add_tri(BMESH *mesh, Patch *patch, const OBJFace &face,
01230                        unsigned long idx0, unsigned long idx1, unsigned long idx2) const
01231 {
01232    
01233    // Make sure vertex indices are good:
01234    assert((face.get_vertex_idx(idx0) > 0) &&
01235           (face.get_vertex_idx(idx0) <= vertices.size()) &&
01236           (face.get_vertex_idx(idx1) > 0) &&
01237           (face.get_vertex_idx(idx1) <= vertices.size()) &&
01238           (face.get_vertex_idx(idx2) > 0) &&
01239           (face.get_vertex_idx(idx2) <= vertices.size()));
01240    
01241    // Make sure texture coordinate indices are good:
01242    assert(!face.has_texcoords() ||
01243           ((face.get_texcoord_idx(idx0) > 0) &&
01244            (face.get_texcoord_idx(idx0) <= texcoords.size()) &&
01245            (face.get_texcoord_idx(idx1) > 0) &&
01246            (face.get_texcoord_idx(idx1) <= texcoords.size()) &&
01247            (face.get_texcoord_idx(idx2) > 0) &&
01248            (face.get_texcoord_idx(idx2) <= texcoords.size())));
01249    
01250    // Make sure normal indices are good:
01251    assert(!face.has_normals() ||
01252           ((face.get_normal_idx(idx0) > 0) &&
01253            (face.get_normal_idx(idx0) <= normals.size()) &&
01254            (face.get_normal_idx(idx1) > 0) &&
01255            (face.get_normal_idx(idx1) <= normals.size()) &&
01256            (face.get_normal_idx(idx2) > 0) &&
01257            (face.get_normal_idx(idx2) <= normals.size())));
01258    
01259    if(face.has_texcoords()){
01260       
01261       mesh->add_face(face.get_vertex_idx(idx0) - 1,
01262                      face.get_vertex_idx(idx1) - 1,
01263                      face.get_vertex_idx(idx2) - 1,
01264                      texcoords[face.get_texcoord_idx(idx0) - 1],
01265                      texcoords[face.get_texcoord_idx(idx1) - 1],
01266                      texcoords[face.get_texcoord_idx(idx2) - 1],
01267                      patch);
01268       
01269    } else {
01270       
01271       mesh->add_face(face.get_vertex_idx(idx0) - 1,
01272                      face.get_vertex_idx(idx1) - 1,
01273                      face.get_vertex_idx(idx2) - 1,
01274                      patch);
01275       
01276    }
01277    
01278 }
01279 
01280 void
01281 OBJReaderImpl::add_creases(BMESH *mesh) const
01282 {
01283    
01284    for(int ei = 0; ei < mesh->nedges(); ++ei){
01285       
01286       Bedge *cur_edge = mesh->be(ei);
01287       
01288       // Skip boundary edges:
01289       if((cur_edge->f1() == 0) || (cur_edge->f2() == 0))
01290          continue;
01291       
01292       // Skip edges that inside a single obj face:
01293       if(mesh_faces2obj_faces[cur_edge->f1()->index()] ==
01294          mesh_faces2obj_faces[cur_edge->f2()->index()])
01295          continue;
01296       
01297       // Skip edges adjacent to faces that have no normals:
01298       if(!faces[mesh_faces2obj_faces[cur_edge->f1()->index()]].has_normals() ||
01299          !faces[mesh_faces2obj_faces[cur_edge->f2()->index()]].has_normals())
01300          continue;
01301       
01302       int vertex_indices[2];
01303       vertex_indices[0] = cur_edge->v1()->index();
01304       vertex_indices[1] = cur_edge->v2()->index();
01305       
01306       // Indexed by vertex, then by face:
01307       int normal_indices[2][2] = {{-1, -1}, {-1, -1}};
01308       
01309       for(int fi = 0; fi < 2; ++fi){
01310          
01311          unsigned long obj_face_idx = mesh_faces2obj_faces[cur_edge->f(fi + 1)->index()];
01312          
01313          for (uint vi = 0; vi < faces[obj_face_idx].num_vertices(); ++vi){
01314             
01315             for (int evi = 0; evi < 2; ++evi){
01316                
01317                if (vertex_indices[evi] ==
01318                    int(faces[obj_face_idx].get_vertex_idx(vi) - 1)) {
01319                   
01320                   normal_indices[evi][fi] =
01321                      faces[obj_face_idx].get_normal_idx(vi);
01322                   
01323                }
01324                
01325             }
01326          
01327          }
01328          
01329       }
01330       
01331       // Make sure all normal indices were set:
01332       assert(normal_indices[0][0] != -1);
01333       assert(normal_indices[0][1] != -1);
01334       assert(normal_indices[1][0] != -1);
01335       assert(normal_indices[1][1] != -1);
01336       
01337       if((normal_indices[0][0] != normal_indices[0][1]) ||
01338          (normal_indices[1][0] != normal_indices[1][1])){
01339          
01340          cur_edge->set_crease();
01341          
01342       }
01343       
01344    }
01345    
01346 }
01347 
01348 //----------------------------------------------------------------------------//
01349 
01350 OBJReader::OBJReader()
01351    : impl(0)
01352 {
01353    
01354    impl = new OBJReaderImpl();
01355    
01356 }
01357 
01358 OBJReader::~OBJReader()
01359 {
01360    
01361    delete impl;
01362    
01363 }
01364       
01365 /*!
01366  *  \return \c true if .obj file data was read off the stream \p in successfully
01367  *  and \c false otherwise.
01368  *
01369  */
01370 bool
01371 OBJReader::read(istream &in)
01372 {
01373    
01374    return impl->read(in);
01375    
01376 }
01377 
01378 BMESH*
01379 OBJReader::get_mesh() const
01380 {
01381    
01382    return impl->get_mesh();
01383    
01384 }
01385 
01386 void
01387 OBJReader::get_mesh(BMESH *mesh) const
01388 {
01389    
01390    impl->get_mesh(mesh);
01391    
01392 }
01393 
01394 //----------------------------------------------------------------------------//
01395 
01396 unsigned long
01397 OBJReader::get_num_vertices() const
01398 {
01399    
01400    return impl->vertices.size();
01401    
01402 }
01403 
01404 unsigned long
01405 OBJReader::get_num_texcoords() const
01406 {
01407    
01408    return impl->texcoords.size();
01409    
01410 }
01411 
01412 unsigned long
01413 OBJReader::get_num_normals() const
01414 {
01415    
01416    return impl->normals.size();
01417    
01418 }
01419 
01420 unsigned long
01421 OBJReader::get_num_faces() const
01422 {
01423    
01424    return impl->faces.size();
01425    
01426 }
01427 
01428 unsigned long
01429 OBJReader::get_num_materials() const
01430 {
01431    
01432    return impl->materials.size();
01433    
01434 }
01435 
01436 unsigned long
01437 OBJReader::get_num_material_libs() const
01438 {
01439    
01440    return impl->mtl_files.size();
01441    
01442 }

Generated on Mon Sep 18 11:39:32 2006 for jot by  doxygen 1.4.4