Panda3D

objToEggConverter.cxx

00001 // Filename: objToEggConverter.cxx
00002 // Created by:  drose (07Dec10)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "objToEggConverter.h"
00016 #include "config_objegg.h"
00017 #include "eggData.h"
00018 #include "string_utils.h"
00019 #include "streamReader.h"
00020 #include "virtualFileSystem.h"
00021 #include "eggPolygon.h"
00022 #include "dcast.h"
00023 
00024 ////////////////////////////////////////////////////////////////////
00025 //     Function: ObjToEggConverter::Constructor
00026 //       Access: Public
00027 //  Description:
00028 ////////////////////////////////////////////////////////////////////
00029 ObjToEggConverter::
00030 ObjToEggConverter() {
00031 }
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: ObjToEggConverter::Copy Constructor
00035 //       Access: Public
00036 //  Description:
00037 ////////////////////////////////////////////////////////////////////
00038 ObjToEggConverter::
00039 ObjToEggConverter(const ObjToEggConverter &copy) :
00040   SomethingToEggConverter(copy)
00041 {
00042 }
00043 
00044 ////////////////////////////////////////////////////////////////////
00045 //     Function: ObjToEggConverter::Destructor
00046 //       Access: Public
00047 //  Description:
00048 ////////////////////////////////////////////////////////////////////
00049 ObjToEggConverter::
00050 ~ObjToEggConverter() {
00051 }
00052 
00053 ////////////////////////////////////////////////////////////////////
00054 //     Function: ObjToEggConverter::make_copy
00055 //       Access: Public, Virtual
00056 //  Description: Allocates and returns a new copy of the converter.
00057 ////////////////////////////////////////////////////////////////////
00058 SomethingToEggConverter *ObjToEggConverter::
00059 make_copy() {
00060   return new ObjToEggConverter(*this);
00061 }
00062 
00063 
00064 ////////////////////////////////////////////////////////////////////
00065 //     Function: ObjToEggConverter::get_name
00066 //       Access: Public, Virtual
00067 //  Description: Returns the English name of the file type this
00068 //               converter supports.
00069 ////////////////////////////////////////////////////////////////////
00070 string ObjToEggConverter::
00071 get_name() const {
00072   return "obj";
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: ObjToEggConverter::get_extension
00077 //       Access: Public, Virtual
00078 //  Description: Returns the common extension of the file type this
00079 //               converter supports.
00080 ////////////////////////////////////////////////////////////////////
00081 string ObjToEggConverter::
00082 get_extension() const {
00083   return "obj";
00084 }
00085 
00086 ////////////////////////////////////////////////////////////////////
00087 //     Function: ObjToEggConverter::supports_compressed
00088 //       Access: Published, Virtual
00089 //  Description: Returns true if this file type can transparently load
00090 //               compressed files (with a .pz extension), false
00091 //               otherwise.
00092 ////////////////////////////////////////////////////////////////////
00093 bool ObjToEggConverter::
00094 supports_compressed() const {
00095   return true;
00096 }
00097 
00098 ////////////////////////////////////////////////////////////////////
00099 //     Function: ObjToEggConverter::convert_file
00100 //       Access: Public, Virtual
00101 //  Description: Handles the reading of the input file and converting
00102 //               it to egg.  Returns true if successful, false
00103 //               otherwise.
00104 ////////////////////////////////////////////////////////////////////
00105 bool ObjToEggConverter::
00106 convert_file(const Filename &filename) {
00107   clear_error();
00108 
00109   if (_egg_data->get_coordinate_system() == CS_default) {
00110     _egg_data->set_coordinate_system(CS_zup_right);
00111   }
00112 
00113   if (!process(filename)) {
00114     _error = true;
00115   }
00116   return !had_error();
00117 }
00118 
00119 ////////////////////////////////////////////////////////////////////
00120 //     Function: ObjToEggConverter::process
00121 //       Access: Protected
00122 //  Description: 
00123 ////////////////////////////////////////////////////////////////////
00124 bool ObjToEggConverter::
00125 process(const Filename &filename) {
00126   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00127   istream *strm = vfs->open_read_file(filename, true);
00128   if (strm == NULL) {
00129     objegg_cat.error() 
00130       << "Couldn't read " << filename << "\n";
00131     return false;
00132   }
00133 
00134   _vi = 1;
00135   _vti = 1;
00136   _vni = 1;
00137 
00138   _vpool = new EggVertexPool("vpool");
00139   _egg_data->add_child(_vpool);
00140   _root_group = new EggGroup("root");
00141   _egg_data->add_child(_root_group);
00142   _current_group = _root_group;
00143 
00144   StreamReader sr(strm, true);
00145   string line = sr.readline();
00146   _line_number = 1;
00147   while (!line.empty()) {
00148     line = trim(line);
00149     if (line.empty()) {
00150       line = sr.readline();
00151       continue;
00152     }
00153 
00154     if (line[0] == '#') {
00155       line = sr.readline();
00156       continue;
00157     }
00158 
00159     if (!process_line(line)) {
00160       return false;
00161     }
00162     line = sr.readline();
00163     ++_line_number;
00164   }
00165 
00166   return true;
00167 }
00168 
00169 ////////////////////////////////////////////////////////////////////
00170 //     Function: ObjToEggConverter::process_line
00171 //       Access: Protected
00172 //  Description: 
00173 ////////////////////////////////////////////////////////////////////
00174 bool ObjToEggConverter::
00175 process_line(const string &line) {
00176   vector_string words;
00177   tokenize(line, words, " \t", true);
00178   nassertr(!words.empty(), false);
00179 
00180   string tag = words[0];
00181   if (tag == "v") {
00182     return process_v(words);
00183   } else if (tag == "vt") {
00184     return process_vt(words);
00185   } else if (tag == "vn") {
00186     return process_vn(words);
00187   } else if (tag == "f") {
00188     return process_f(words);
00189   } else if (tag == "g") {
00190     return process_g(words);
00191   } else {
00192     bool inserted = _ignored_tags.insert(tag).second;
00193     if (inserted) {
00194       objegg_cat.info()
00195         << "Ignoring tag " << tag << "\n";
00196     }
00197   }
00198 
00199   return true;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: ObjToEggConverter::process_v
00204 //       Access: Protected
00205 //  Description: 
00206 ////////////////////////////////////////////////////////////////////
00207 bool ObjToEggConverter::
00208 process_v(vector_string &words) {
00209   if (words.size() != 4 && words.size() != 7) {
00210     objegg_cat.error()
00211       << "Wrong number of tokens at line " << _line_number << "\n";
00212     return false;
00213   }
00214   
00215   bool okflag = true;
00216   LPoint3d pos;
00217   okflag &= string_to_double(words[1], pos[0]);
00218   okflag &= string_to_double(words[2], pos[1]);
00219   okflag &= string_to_double(words[3], pos[2]);
00220 
00221   if (!okflag) {
00222     objegg_cat.error()
00223       << "Invalid number at line " << _line_number << "\n";
00224     return false;
00225   }
00226 
00227   EggVertex *vertex = get_vertex(_vi);
00228   vertex->set_pos(pos);
00229 
00230   // Meshlab format might include an RGB color following the vertex
00231   // position.
00232   if (words.size() == 7) {
00233     double r, g, b;
00234     okflag &= string_to_double(words[4], r);
00235     okflag &= string_to_double(words[5], g);
00236     okflag &= string_to_double(words[6], b);
00237 
00238     if (!okflag) {
00239       objegg_cat.error()
00240         << "Invalid number at line " << _line_number << "\n";
00241       return false;
00242     }
00243     vertex->set_color(LColor(r, g, b, 1.0));
00244   }
00245 
00246   ++_vi;
00247 
00248   return true;
00249 }
00250 
00251 ////////////////////////////////////////////////////////////////////
00252 //     Function: ObjToEggConverter::process_vt
00253 //       Access: Protected
00254 //  Description: 
00255 ////////////////////////////////////////////////////////////////////
00256 bool ObjToEggConverter::
00257 process_vt(vector_string &words) {
00258   if (words.size() != 3 && words.size() != 4) {
00259     objegg_cat.error()
00260       << "Wrong number of tokens at line " << _line_number << "\n";
00261     return false;
00262   }
00263   
00264   bool okflag = true;
00265   LTexCoord3d uvw;
00266   okflag &= string_to_double(words[1], uvw[0]);
00267   okflag &= string_to_double(words[2], uvw[1]);
00268   if (words.size() == 4) {
00269     okflag &= string_to_double(words[3], uvw[2]);
00270   }
00271 
00272   if (!okflag) {
00273     objegg_cat.error()
00274       << "Invalid number at line " << _line_number << "\n";
00275     return false;
00276   }
00277 
00278   EggVertex *vertex = get_vertex(_vti);
00279   if (words.size() == 4) {
00280     vertex->set_uvw("", uvw);
00281   } else {
00282     vertex->set_uv("", LTexCoordd(uvw[0], uvw[1]));
00283   }
00284   ++_vti;
00285 
00286   return true;
00287 }
00288 
00289 ////////////////////////////////////////////////////////////////////
00290 //     Function: ObjToEggConverter::process_vn
00291 //       Access: Protected
00292 //  Description: 
00293 ////////////////////////////////////////////////////////////////////
00294 bool ObjToEggConverter::
00295 process_vn(vector_string &words) {
00296   if (words.size() != 4) {
00297     objegg_cat.error()
00298       << "Wrong number of tokens at line " << _line_number << "\n";
00299     return false;
00300   }
00301   
00302   bool okflag = true;
00303   LVector3d normal;
00304   okflag &= string_to_double(words[1], normal[0]);
00305   okflag &= string_to_double(words[2], normal[1]);
00306   okflag &= string_to_double(words[3], normal[2]);
00307 
00308   if (!okflag) {
00309     objegg_cat.error()
00310       << "Invalid number at line " << _line_number << "\n";
00311     return false;
00312   }
00313   normal.normalize();
00314 
00315   EggVertex *vertex = get_vertex(_vni);
00316   vertex->set_normal(normal);
00317   ++_vni;
00318 
00319   return true;
00320 }
00321 
00322 ////////////////////////////////////////////////////////////////////
00323 //     Function: ObjToEggConverter::process_f
00324 //       Access: Protected
00325 //  Description: Defines a face in the obj file.
00326 ////////////////////////////////////////////////////////////////////
00327 bool ObjToEggConverter::
00328 process_f(vector_string &words) {
00329   PT(EggPolygon) poly = new EggPolygon;
00330   for (size_t i = 1; i < words.size(); ++i) {
00331     EggVertex *vertex = get_face_vertex(words[i]);
00332     if (vertex == NULL) {
00333       return false;
00334     }
00335     poly->add_vertex(vertex);
00336   }
00337   _current_group->add_child(poly);
00338 
00339   return true;
00340 }
00341 
00342 ////////////////////////////////////////////////////////////////////
00343 //     Function: ObjToEggConverter::process_g
00344 //       Access: Protected
00345 //  Description: Defines a group in the obj file.
00346 ////////////////////////////////////////////////////////////////////
00347 bool ObjToEggConverter::
00348 process_g(vector_string &words) {
00349   EggGroup *group = _root_group;
00350 
00351   // We assume the group names define a hierarchy of more-specific to
00352   // less-specific group names, so that the first group name is the
00353   // bottommost node, and the last group name is the topmost node.
00354 
00355   // Thus, iterate from the back to the front.
00356   size_t i = words.size();
00357   while (i != 0) {
00358     --i;
00359     EggNode *child = group->find_child(words[i]);
00360     if (child == NULL || !child->is_of_type(EggGroup::get_class_type())) {
00361       child = new EggGroup(words[i]);
00362       group->add_child(child);
00363     }
00364     group = DCAST(EggGroup, child);
00365   }
00366 
00367   _current_group = group;
00368   return true;
00369 }
00370 
00371 ////////////////////////////////////////////////////////////////////
00372 //     Function: ObjToEggConverter::get_vertex
00373 //       Access: Protected
00374 //  Description: Returns or creates a vertex in the vpool with the
00375 //               given index.
00376 ////////////////////////////////////////////////////////////////////
00377 EggVertex *ObjToEggConverter::
00378 get_vertex(int n) {
00379   if (n < 0) {
00380     // A negative index means to count backward from the end.
00381     n = _vi + n;
00382   }
00383   EggVertex *vertex = _vpool->get_vertex(n);
00384   if (vertex == NULL) {
00385     vertex = new EggVertex;
00386     _vpool->add_vertex(vertex, n);
00387   }
00388 
00389   return vertex;
00390 }
00391 
00392 ////////////////////////////////////////////////////////////////////
00393 //     Function: ObjToEggConverter::get_face_vertex
00394 //       Access: Protected
00395 //  Description: Returns or creates a vertex in the vpool according to
00396 //               the indicated face reference.
00397 ////////////////////////////////////////////////////////////////////
00398 EggVertex *ObjToEggConverter::
00399 get_face_vertex(const string &reference) {
00400   vector_string words;
00401   tokenize(reference, words, "/", false);
00402   nassertr(!words.empty(), NULL);
00403 
00404   vector<EggVertex *> vertices;
00405   vertices.reserve(words.size());
00406   for (size_t i = 0; i < words.size(); ++i) {
00407     if (trim(words[i]).empty()) {
00408       if (i == 0) {
00409         objegg_cat.error()                    
00410           << "Invalid null vertex at line " << _line_number << "\n";
00411         return NULL;
00412       } else {
00413         vertices.push_back(vertices[0]);
00414         continue;
00415       }
00416     }
00417 
00418     int index;
00419     if (!string_to_int(words[i], index)) {
00420       objegg_cat.error()
00421         << "Invalid integer " << words[i] << " at line " << _line_number << "\n";
00422       return NULL;
00423     }
00424     EggVertex *vertex = get_vertex(index);
00425     if (vertex == NULL){ 
00426       objegg_cat.error()
00427         << "Invalid vertex " << index << " at line " << _line_number << "\n";
00428       return NULL;
00429     }
00430     vertices.push_back(vertex);
00431   }
00432   nassertr(!vertices.empty(), NULL);
00433   nassertr(vertices.size() == words.size(), NULL);
00434 
00435   if (vertices.size() == 1) {
00436     // Just a pos reference.
00437     return vertices[0];
00438 
00439   } else if (vertices.size() == 2) {
00440     // Pos + uv.
00441     if (vertices[0] == vertices[1]) {
00442       return vertices[0];
00443     }
00444     // Synthesize a vertex.
00445     EggVertex synth(*vertices[0]);
00446     if (vertices[1]->has_uv("")) {
00447       synth.set_uv("", vertices[1]->get_uv(""));
00448     } else if (vertices[1]->has_uvw("")) {
00449       synth.set_uvw("", vertices[1]->get_uvw(""));
00450     }
00451 
00452     return _vpool->create_unique_vertex(synth);
00453 
00454   } else if (vertices.size() >= 3) {
00455     // pos + uv + normal.
00456     if (vertices[0] == vertices[1] && vertices[0] == vertices[2]) {
00457       return vertices[0];
00458     }
00459 
00460     // Synthesize a vertex.
00461     EggVertex synth(*vertices[0]);
00462     if (vertices[1]->has_uv("")) {
00463       synth.set_uv("", vertices[1]->get_uv(""));
00464     } else if (vertices[1]->has_uvw("")) {
00465       synth.set_uvw("", vertices[1]->get_uvw(""));
00466     }
00467     if (vertices[2]->has_normal()) {
00468       synth.set_normal(vertices[2]->get_normal());
00469     }
00470 
00471     return _vpool->create_unique_vertex(synth);
00472   }
00473 
00474   return NULL;
00475 }
 All Classes Functions Variables Enumerations