Panda3D
|
00001 // Filename: mayaToEgg_server.cxx 00002 // Adapted by: cbrunner (09Nov09) 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 #if defined(WIN32_VC) || defined(WIN64_VC) 00016 #include <direct.h> // for chdir 00017 #endif 00018 #include "mayaToEgg_server.h" 00019 #include "mayaToEggConverter.h" 00020 #include "config_mayaegg.h" 00021 #include "config_maya.h" // for maya_cat 00022 #include "globPattern.h" 00023 #ifdef _WIN32 00024 #include "pystub.h" 00025 #endif 00026 00027 //////////////////////////////////////////////////////////////////// 00028 // Function: MayaToEggServer::Constructor 00029 // Access: Public 00030 // Description: 00031 //////////////////////////////////////////////////////////////////// 00032 MayaToEggServer:: 00033 MayaToEggServer() : 00034 SomethingToEgg("Maya", ".mb") 00035 { 00036 add_path_replace_options(); 00037 add_path_store_options(); 00038 add_animation_options(); 00039 add_units_options(); 00040 add_normals_options(); 00041 add_transform_options(); 00042 00043 set_program_description 00044 ("This program converts Maya model files to egg. Static and animatable " 00045 "models can be converted, with polygon or NURBS output. Animation tables " 00046 "can also be generated to apply to an animatable model."); 00047 00048 add_option 00049 ("p", "", 0, 00050 "Generate polygon output only. Tesselate all NURBS surfaces to " 00051 "polygons via the built-in Maya tesselator. The tesselation will " 00052 "be based on the tolerance factor given by -ptol.", 00053 &MayaToEggServer::dispatch_none, &_polygon_output); 00054 00055 add_option 00056 ("ptol", "tolerance", 0, 00057 "Specify the fit tolerance for Maya polygon tesselation. The smaller " 00058 "the number, the more polygons will be generated. The default is " 00059 "0.01.", 00060 &MayaToEggServer::dispatch_double, NULL, &_polygon_tolerance); 00061 00062 add_option 00063 ("bface", "", 0, 00064 "Respect the Maya \"double sided\" rendering flag to indicate whether " 00065 "polygons should be double-sided or single-sided. Since this flag " 00066 "is set to double-sided by default in Maya, it is often better to " 00067 "ignore this flag (unless your modelers are diligent in turning it " 00068 "off where it is not desired). If this flag is not specified, the " 00069 "default is to treat all polygons as single-sided, unless an " 00070 "egg object type of \"double-sided\" is set.", 00071 &MayaToEggServer::dispatch_none, &_respect_maya_double_sided); 00072 00073 add_option 00074 ("suppress-vcolor", "", 0, 00075 "Ignore vertex color for geometry that has a texture applied. " 00076 "(This is the way Maya normally renders internally.) The egg flag " 00077 "'vertex-color' may be applied to a particular model to override " 00078 "this setting locally.", 00079 &MayaToEggServer::dispatch_none, &_suppress_vertex_color); 00080 00081 add_option 00082 ("keep-uvs", "", 0, 00083 "Convert all UV sets on all vertices, even those that do not appear " 00084 "to be referenced by any textures.", 00085 &MayaToEggServer::dispatch_none, &_keep_all_uvsets); 00086 00087 add_option 00088 ("round-uvs", "", 0, 00089 "round up uv coordinates to the nearest 1/100th. i.e. -0.001 becomes" 00090 "0.0; 0.444 becomes 0.44; 0.778 becomes 0.78.", 00091 &MayaToEggServer::dispatch_none, &_round_uvs); 00092 00093 add_option 00094 ("copytex","dir",0, 00095 "copy the textures to a ""Textures"" sub directory relative to the written out egg file." 00096 """dir"" is a sub directory in the same format as those used by -pr, etc." , 00097 &MayaToEggServer::dispatch_filename, &_texture_copy, &_texture_out_dir); 00098 00099 add_option 00100 ("trans", "type", 0, 00101 "Specifies which transforms in the Maya file should be converted to " 00102 "transforms in the egg file. The option may be one of all, model, " 00103 "dcs, or none. The default is model, which means only transforms on " 00104 "nodes that have the model flag or the dcs flag are preserved.", 00105 &MayaToEggServer::dispatch_transform_type, NULL, &_transform_type); 00106 00107 add_option 00108 ("subroot", "name", 0, 00109 "Specifies that only a subroot of the geometry in the Maya file should " 00110 "be converted; specifically, the geometry under the node or nodes whose " 00111 "name matches the parameter (which may include globbing characters " 00112 "like * or ?). This parameter may be repeated multiple times to name " 00113 "multiple roots. If it is omitted altogether, the entire file is " 00114 "converted.", 00115 &MayaToEggServer::dispatch_vector_string, NULL, &_subroots); 00116 00117 add_option 00118 ("subset", "name", 0, 00119 "Specifies that only a subset of the geometry in the Maya file should " 00120 "be converted; specifically, the geometry under the node or nodes whose " 00121 "name matches the parameter (which may include globbing characters " 00122 "like * or ?). This parameter may be repeated multiple times to name " 00123 "multiple roots. If it is omitted altogether, the entire file is " 00124 "converted.", 00125 &MayaToEggServer::dispatch_vector_string, NULL, &_subsets); 00126 00127 add_option 00128 ("exclude", "name", 0, 00129 "Specifies that a subset of the geometry in the Maya file should " 00130 "not be converted; specifically, the geometry under the node or nodes whose " 00131 "name matches the parameter (which may include globbing characters " 00132 "like * or ?). This parameter may be repeated multiple times to name " 00133 "multiple roots.", 00134 &MayaToEggServer::dispatch_vector_string, NULL, &_excludes); 00135 00136 add_option 00137 ("ignore-slider", "name", 0, 00138 "Specifies the name of a slider (blend shape deformer) that maya2egg " 00139 "should not process. The slider will not be touched during conversion " 00140 "and it will not become a part of the animation. This " 00141 "parameter may including globbing characters, and it may be repeated " 00142 "as needed.", 00143 &MayaToEggServer::dispatch_vector_string, NULL, &_ignore_sliders); 00144 00145 add_option 00146 ("force-joint", "name", 0, 00147 "Specifies the name of a DAG node that maya2egg " 00148 "should treat as a joint, even if it does not appear to be a Maya joint " 00149 "and does not appear to be animated.", 00150 &MayaToEggServer::dispatch_vector_string, NULL, &_force_joints); 00151 00152 add_option 00153 ("v", "", 0, 00154 "Increase verbosity. More v's means more verbose.", 00155 &MayaToEggServer::dispatch_count, NULL, &_verbose); 00156 00157 add_option 00158 ("legacy-shaders", "", 0, 00159 "Use this flag to turn off modern (Phong) shader generation" 00160 "and treat all shaders as if they were Lamberts (legacy).", 00161 &MayaToEggServer::dispatch_none, &_legacy_shader); 00162 00163 // Unfortunately, the Maya API doesn't allow us to differentiate 00164 // between relative and absolute pathnames--everything comes out as 00165 // an absolute pathname, even if it is stored in the Maya file as a 00166 // relative path. So we can't support -noabs. 00167 remove_option("noabs"); 00168 00169 _verbose = 0; 00170 _polygon_tolerance = 0.01; 00171 _transform_type = MayaToEggConverter::TT_model; 00172 _got_tbnauto = true; 00173 qManager = new QueuedConnectionManager(); 00174 qListener = new QueuedConnectionListener(qManager, 0); 00175 qReader = new QueuedConnectionReader(qManager, 0); 00176 cWriter = new ConnectionWriter(qManager, 0); 00177 dummy = new MayaToEggConverter(); 00178 00179 nout << "Initializing Maya...\n"; 00180 if (!dummy->open_api()) { 00181 nout << "Unable to initialize Maya.\n"; 00182 exit(1); 00183 } 00184 } 00185 //////////////////////////////////////////////////////////////////// 00186 // Function: MayaToEggServer::Destructor 00187 // Access: Public 00188 // Description: 00189 //////////////////////////////////////////////////////////////////// 00190 MayaToEggServer:: 00191 ~MayaToEggServer() { 00192 delete qManager; 00193 delete qReader; 00194 delete qListener; 00195 delete cWriter; 00196 delete dummy; 00197 } 00198 00199 //////////////////////////////////////////////////////////////////// 00200 // Function: MayaToEggServer::run 00201 // Access: Public 00202 // Description: 00203 //////////////////////////////////////////////////////////////////// 00204 void MayaToEggServer:: 00205 run() { 00206 // Make sure we have good clean data to start with 00207 _data = new EggData(); 00208 00209 // Set the verbose level by using Notify. 00210 if (_verbose >= 3) { 00211 maya_cat->set_severity(NS_spam); 00212 mayaegg_cat->set_severity(NS_spam); 00213 } else if (_verbose >= 2) { 00214 maya_cat->set_severity(NS_debug); 00215 mayaegg_cat->set_severity(NS_debug); 00216 } else if (_verbose >= 1) { 00217 maya_cat->set_severity(NS_info); 00218 mayaegg_cat->set_severity(NS_info); 00219 } 00220 00221 // Let's convert the output file to a full path before we initialize 00222 // Maya, since Maya now has a nasty habit of changing the current 00223 // directory. 00224 if (_got_output_filename) { 00225 _output_filename.make_absolute(); 00226 //conjunct the relative output path with output file's dir weifengh 00227 if (_texture_out_dir.is_local()) { 00228 Filename tempdir = _output_filename.get_dirname() + "/"; 00229 _texture_out_dir = tempdir + _texture_out_dir; 00230 } 00231 } 00232 00233 // So our relative path names come out correctly 00234 _path_replace->_path_directory = get_output_filename().get_dirname(); 00235 00236 MayaToEggConverter converter(_program_name); 00237 00238 // Copy in the command-line parameters. 00239 converter._polygon_output = _polygon_output; 00240 converter._polygon_tolerance = _polygon_tolerance; 00241 converter._respect_maya_double_sided = _respect_maya_double_sided; 00242 converter._always_show_vertex_color = !_suppress_vertex_color; 00243 converter._keep_all_uvsets = _keep_all_uvsets; 00244 converter._round_uvs = _round_uvs; 00245 converter._transform_type = _transform_type; 00246 converter._texture_copy = _texture_copy; 00247 converter._texture_out_dir = _texture_out_dir; 00248 converter._legacy_shader = _legacy_shader; 00249 00250 vector_string::const_iterator si; 00251 if (!_subroots.empty()) { 00252 converter.clear_subroots(); 00253 for (si = _subroots.begin(); si != _subroots.end(); ++si) { 00254 converter.add_subroot(GlobPattern(*si)); 00255 } 00256 } 00257 00258 if (!_subsets.empty()) { 00259 converter.clear_subsets(); 00260 for (si = _subsets.begin(); si != _subsets.end(); ++si) { 00261 converter.add_subset(GlobPattern(*si)); 00262 } 00263 } 00264 00265 if (!_excludes.empty()) { 00266 converter.clear_excludes(); 00267 for (si = _excludes.begin(); si != _excludes.end(); ++si) { 00268 converter.add_exclude(GlobPattern(*si)); 00269 } 00270 } 00271 00272 if (!_ignore_sliders.empty()) { 00273 converter.clear_ignore_sliders(); 00274 for (si = _ignore_sliders.begin(); si != _ignore_sliders.end(); ++si) { 00275 converter.add_ignore_slider(GlobPattern(*si)); 00276 } 00277 } 00278 00279 if (!_force_joints.empty()) { 00280 converter.clear_force_joints(); 00281 for (si = _force_joints.begin(); si != _force_joints.end(); ++si) { 00282 converter.add_force_joint(GlobPattern(*si)); 00283 } 00284 } 00285 00286 // Copy in the path and animation parameters. 00287 apply_parameters(converter); 00288 00289 // Set the coordinate system to match Maya's. 00290 if (!_got_coordinate_system) { 00291 _coordinate_system = converter._maya->get_coordinate_system(); 00292 } 00293 _data->set_coordinate_system(_coordinate_system); 00294 00295 converter.set_egg_data(_data); 00296 00297 if (!converter.convert_file(_input_filename)) { 00298 nout << "Errors in conversion.\n"; 00299 exit(1); 00300 } 00301 00302 // Use the standard Maya units, if the user didn't specify 00303 // otherwise. This always returns centimeters, which is the way all 00304 // Maya files are stored internally (and is the units returned by 00305 // all of the API functions called here). 00306 if (_input_units == DU_invalid) { 00307 _input_units = converter.get_input_units(); 00308 } 00309 00310 // Add the command line comment at the top of the egg file 00311 append_command_comment(_data); 00312 00313 write_egg_file(); 00314 00315 // Clean and out 00316 close_output(); 00317 _verbose = 0; 00318 _polygon_tolerance = 0.01; 00319 _polygon_output = 0; 00320 _transform_type = MayaToEggConverter::TT_model; 00321 _subsets.clear(); 00322 _subroots.clear(); 00323 _input_units = DU_invalid; 00324 _output_units = DU_invalid; 00325 _excludes.clear(); 00326 _ignore_sliders.clear(); 00327 _force_joints.clear(); 00328 _got_transform = false; 00329 _transform = LMatrix4d::ident_mat(); 00330 _normals_mode = NM_preserve; 00331 _normals_threshold = 0.0; 00332 _got_start_frame = false; 00333 _got_end_frame = false; 00334 _got_frame_inc = false; 00335 _got_neutral_frame = false; 00336 _got_input_frame_rate = false; 00337 _got_output_frame_rate = false; 00338 _got_output_filename = false; 00339 _merge_externals = false; 00340 _got_tbnall = false; 00341 _got_tbnauto = false; 00342 _got_transform = false; 00343 _coordinate_system = CS_yup_right; 00344 _noabs = false; 00345 _program_args.clear(); 00346 _data->clear(); 00347 _animation_convert = AC_none; 00348 _character_name = ""; 00349 dummy->clear(); 00350 } 00351 00352 //////////////////////////////////////////////////////////////////// 00353 // Function: MayaToEggServer::dispatch_transform_type 00354 // Access: Protected, Static 00355 // Description: Dispatches a parameter that expects a 00356 // MayaToEggConverter::TransformType option. 00357 //////////////////////////////////////////////////////////////////// 00358 bool MayaToEggServer:: 00359 dispatch_transform_type(const string &opt, const string &arg, void *var) { 00360 MayaToEggConverter::TransformType *ip = (MayaToEggConverter::TransformType *)var; 00361 (*ip) = MayaToEggConverter::string_transform_type(arg); 00362 00363 if ((*ip) == MayaToEggConverter::TT_invalid) { 00364 nout << "Invalid type for -" << opt << ": " << arg << "\n" 00365 << "Valid types are all, model, dcs, and none.\n"; 00366 return false; 00367 } 00368 00369 return true; 00370 } 00371 00372 //////////////////////////////////////////////////////////////////// 00373 // Function: MayaToEggServer::poll 00374 // Access: Public 00375 // Description: Checks for any network activity and handles it, if 00376 // appropriate, and then returns. This must be called 00377 // periodically 00378 //////////////////////////////////////////////////////////////////// 00379 void MayaToEggServer:: 00380 poll() { 00381 // Listen for new connections 00382 qListener->poll(); 00383 00384 // If we have a new connection from a client create a new connection 00385 // pointer and add it to the reader list 00386 if (qListener->new_connection_available()) { 00387 PT(Connection) con; 00388 PT(Connection) rv; 00389 NetAddress address; 00390 if (qListener->get_new_connection(rv, address, con)) { 00391 qReader->add_connection(con); 00392 _clients.insert(con); 00393 } 00394 } 00395 00396 // Check for reset clients 00397 if (qManager->reset_connection_available()) { 00398 PT(Connection) connection; 00399 if (qManager->get_reset_connection(connection)) { 00400 _clients.erase(connection); 00401 qManager->close_connection(connection); 00402 } 00403 } 00404 00405 // Poll the readers (created above) and if they have data process it 00406 qReader->poll(); 00407 if (qReader->data_available()) { 00408 // Grab the incomming data and unpack it 00409 NetDatagram datagram; 00410 if (qReader->get_data(datagram)) { 00411 DatagramIterator data(datagram); 00412 // First data should be the "argc" (argument count) from the client 00413 int argc = data.get_uint8(); 00414 00415 // Now we have to get clever because the rest of the data comes as strings 00416 // and parse_command_line() expects arguments of the standard argc, argv*[] 00417 // variety. 00418 // First, we need a string vector to hold all the strings from the datagram. 00419 // We also need a char * array to keep track of all the pointers we're gonna 00420 // malloc. Needed later for cleanup. 00421 vector_string vargv; 00422 vector<char *> buffers; 00423 00424 // Get the strings from the datagram and put them into the string vector 00425 int i; 00426 for ( i = 0; i < argc; i++ ) { 00427 vargv.push_back(data.get_string()); 00428 } 00429 00430 // Last string is the current directory the client was run from. Not part of 00431 // the argument list, but we still need it 00432 string cwd = data.get_string(); 00433 00434 // We allocate some memory to hold the pointers to the pointers we're going to 00435 // pass in to parse_command_line(). 00436 char ** cargv = (char**) malloc(sizeof(char**) * argc); 00437 00438 // Loop through the string arguments we got from the datagram and convert 00439 // them to const char *'s. parse_command_line() expects char *'s, so we have 00440 // to copy these const versions into fresh char *, since there is no casting 00441 // from const char * to char *. 00442 for ( i = 0; i < argc; i++) { 00443 // string to const char * 00444 const char * cptr = vargv[i].c_str(); 00445 // memory allocated for a new char * of size of the string 00446 char * buffer = (char*) malloc(vargv[i].capacity()+1); 00447 // Copy the const char * to the char * 00448 strcpy(buffer, cptr); 00449 // put this into the arry we defined above. This is what will eventually 00450 // be passed to parse_command_line() 00451 cargv[i] = buffer; 00452 // keep track of the pointers to the allocated memory for cleanup later 00453 buffers.push_back(buffer); 00454 } 00455 // Change to the client's current dir 00456 #ifdef WIN64_VC 00457 _chdir(cwd.c_str()); 00458 #else 00459 chdir(cwd.c_str()); 00460 #endif 00461 00462 // Pass in the 'new' argc and argv we got from the client 00463 this->parse_command_line(argc, cargv); 00464 // Actually run the damn thing 00465 this->run(); 00466 00467 // Cleanup 00468 // First, release the string vector 00469 vargv.clear(); 00470 // No, iterate through the char * vector and cleanup the malloc'd 00471 // pointers 00472 vector<char *>::iterator vi; 00473 for ( vi = buffers.begin() ; vi != buffers.end(); vi++) { 00474 free(*vi); 00475 } 00476 // Clean up the malloc'd pointer pointer 00477 free(cargv); 00478 } // qReader->get_data 00479 00480 Clients::iterator ci; 00481 for (ci = _clients.begin(); ci != _clients.end(); ++ci) { 00482 qManager->close_connection(*ci); 00483 } 00484 } // qReader->data_available 00485 } // poll 00486 00487 int main(int argc, char *argv[]) { 00488 // We don't want pystub on linux, since it gives problems with Maya's python. 00489 #ifdef _WIN32 00490 // A call to pystub() to force libpystub.so to be linked in. 00491 pystub(); 00492 #endif 00493 00494 MayaToEggServer prog; 00495 // Open a rendezvous port for receiving new connections from the client 00496 PT(Connection) rend = prog.qManager->open_TCP_server_rendezvous(4242, 50); 00497 if (rend.is_null()) { 00498 nout << "port opened fail"; 00499 } 00500 00501 // Add this connection to the listeners list 00502 prog.qListener->add_connection(rend); 00503 00504 // Main loop. Keep polling for connections, but don't eat up all the CPU. 00505 while (true) { 00506 prog.poll(); 00507 Thread::force_yield(); 00508 } 00509 return 0; 00510 } 00511