Panda3D
|
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 ©) : 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 }