Panda3D
|
00001 // Filename: mayaApi.cxx 00002 // Created by: drose (15Apr02) 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 "mayaApi.h" 00016 #include "config_maya.h" 00017 #include "string_utils.h" 00018 #include "thread.h" 00019 00020 #include "pre_maya_include.h" 00021 #include <maya/MGlobal.h> 00022 #include <maya/MDistance.h> 00023 #include <maya/MFileIO.h> 00024 #include <maya/MLibrary.h> 00025 #include <maya/MStatus.h> 00026 #include <maya/MFnAnimCurve.h> 00027 #include "post_maya_include.h" 00028 00029 #ifdef WIN32_VC 00030 #include <direct.h> // for chdir() 00031 #endif 00032 00033 MayaApi *MayaApi::_global_api = (MayaApi *)NULL; 00034 00035 // We need this bogus object just to force the application to link 00036 // with OpenMayaAnim.lib; otherwise, Maya will complain (when compiled 00037 // on Windows) that it is unable to find source plug 'ikRPsolver.msg'. 00038 static MFnAnimCurve force_link_with_OpenMayaAnim; 00039 00040 //////////////////////////////////////////////////////////////////// 00041 // Function: MayaApi::Constructor 00042 // Access: Protected 00043 // Description: Don't attempt to create this object directly; 00044 // instead, use the open_api() method. 00045 //////////////////////////////////////////////////////////////////// 00046 MayaApi:: 00047 MayaApi(const string &program_name, bool view_license, bool revert_dir) { 00048 if (program_name == "plug-in") { 00049 // In this special case, we are invoking the code from within a 00050 // plug-in, so we need not (and should not) call 00051 // MLibrary::initialize(). 00052 _plug_in = true; 00053 _is_valid = true; 00054 return; 00055 } 00056 00057 // Otherwise, if program_name is any other name, we are invoking the 00058 // code from a standalone application and we do need to call 00059 // MLibrary::initialize(). 00060 _plug_in = false; 00061 00062 // Beginning with Maya4.5, the call to initialize seems to change 00063 // the current directory! Yikes! 00064 00065 // Furthermore, the current directory may change during the call to 00066 // any Maya function! Egad! 00067 _cwd = ExecutionEnvironment::get_cwd(); 00068 MStatus stat = MLibrary::initialize(false, (char *)program_name.c_str(), view_license); 00069 00070 int error_count = init_maya_repeat_count; 00071 while (!stat && error_count > 1) { 00072 stat.perror("MLibrary::initialize"); 00073 Thread::sleep(init_maya_timeout); 00074 stat = MLibrary::initialize(false, (char *)program_name.c_str(), view_license); 00075 --error_count; 00076 } 00077 00078 // Restore the current directory. Ever since Maya 2010, there seems to be 00079 // some bad mojo when you do this. 00080 if( revert_dir ){ 00081 string dirname = _cwd.to_os_specific(); 00082 if (chdir(dirname.c_str()) < 0) { 00083 maya_cat.warning() 00084 << "Unable to restore current directory to " << _cwd 00085 << " after initializing Maya.\n"; 00086 } else { 00087 if (maya_cat.is_debug()) { 00088 maya_cat.debug() 00089 << "Restored current directory to " << _cwd << "\n"; 00090 } 00091 } 00092 } 00093 00094 00095 if (!stat) { 00096 stat.perror("MLibrary::initialize"); 00097 _is_valid = false; 00098 } else { 00099 _is_valid = true; 00100 } 00101 } 00102 00103 //////////////////////////////////////////////////////////////////// 00104 // Function: MayaApi::Copy Constructor 00105 // Access: Protected 00106 // Description: Don't attempt to copy MayaApi objects. There should 00107 // be only one of these in the world at a time. 00108 //////////////////////////////////////////////////////////////////// 00109 MayaApi:: 00110 MayaApi(const MayaApi ©) { 00111 nassertv(false); 00112 } 00113 00114 //////////////////////////////////////////////////////////////////// 00115 // Function: MayaApi::Copy Assignment Operator 00116 // Access: Protected 00117 // Description: Don't attempt to copy MayaApi objects. There should 00118 // be only one of these in the world at a time. 00119 //////////////////////////////////////////////////////////////////// 00120 void MayaApi:: 00121 operator = (const MayaApi ©) { 00122 nassertv(false); 00123 } 00124 00125 //////////////////////////////////////////////////////////////////// 00126 // Function: MayaApi::Destructor 00127 // Access: Public 00128 // Description: 00129 //////////////////////////////////////////////////////////////////// 00130 MayaApi:: 00131 ~MayaApi() { 00132 nassertv(_global_api == this); 00133 if (_is_valid && !_plug_in) { 00134 // Caution! Calling this function seems to call exit() somewhere 00135 // within Maya code. 00136 MLibrary::cleanup(); 00137 } 00138 _global_api = (MayaApi *)NULL; 00139 } 00140 00141 //////////////////////////////////////////////////////////////////// 00142 // Function: MayaApi::open_api 00143 // Access: Public, Static 00144 // Description: Opens the Maya API, if it is not already open, and 00145 // returns a pointer representing this connection. When 00146 // you are done using the Maya API, let the pointer 00147 // destruct. 00148 // 00149 // If program_name is supplied, it is passed to Maya as 00150 // the name of the currently-executing program. 00151 // Otherwise, the current program name is extracted from 00152 // the execution environment, if possible. The special 00153 // program_name "plug-in" is used for code that is 00154 // intended to be invoked as a plug-in only; in this 00155 // case, the maya library is not re-initialized. 00156 //////////////////////////////////////////////////////////////////// 00157 PT(MayaApi) MayaApi:: 00158 open_api(string program_name, bool view_license, bool revertdir) { 00159 if (_global_api == (MayaApi *)NULL) { 00160 // We need to create a new MayaApi object. 00161 if (program_name.empty()) { 00162 program_name = ExecutionEnvironment::get_binary_name(); 00163 if (program_name.empty()) { 00164 program_name = "Panda"; 00165 } 00166 } 00167 00168 _global_api = new MayaApi(program_name, view_license, revertdir); 00169 00170 // Try to compare the string-formatted runtime version number with 00171 // the numeric compile-time version number, so we can sanity check 00172 // our runtime environment. (Sure would be nice if Maya provided 00173 // an apples-to-apples comparison for us.) 00174 00175 // According to the Maya specs, the numeric value is derived by 00176 // taking the Maya version number and deleting the '.' characters, 00177 // while also ignoring everything after the second dot (and, for 00178 // some reason, appending a 0). 00179 00180 string runtime_version = MGlobal::mayaVersion().asChar(); 00181 string simple_runtime_version = runtime_version; 00182 runtime_version = trim(runtime_version); 00183 00184 // If the version number contains a space, stop there (that would 00185 // be "service pack 1" or whatever). 00186 size_t space = runtime_version.find(' '); 00187 if (space != string::npos) { 00188 runtime_version = runtime_version.substr(0, space); 00189 } 00190 00191 int rtver_a, rtver_b; 00192 size_t dot1 = runtime_version.find('.'); 00193 if (dot1 == string::npos) { 00194 string_to_int(runtime_version, rtver_a); 00195 rtver_b = 0; 00196 00197 } else { 00198 string_to_int(runtime_version.substr(0, dot1), rtver_a); 00199 00200 size_t dot2 = runtime_version.find('.', dot1 + 1); 00201 if (dot2 == string::npos) { 00202 rtver_b = 0; 00203 } else { 00204 string_to_int(runtime_version.substr(dot1, dot2 - dot1), rtver_b); 00205 simple_runtime_version = runtime_version.substr(0, dot2); 00206 } 00207 } 00208 00209 int runtime_version_int = rtver_a * 100 + rtver_b * 10; 00210 00211 if (maya_cat.is_debug()) { 00212 maya_cat.debug() 00213 << "Compiled with Maya library version " 00214 << (MAYA_API_VERSION / 100) << "." << (MAYA_API_VERSION / 10) % 10 00215 << " (" << MAYA_API_VERSION << "); running with library version " 00216 << runtime_version << ".\n"; 00217 } 00218 00219 if (MAYA_API_VERSION / 10 != runtime_version_int / 10) { 00220 maya_cat.warning() 00221 << "This program was compiled using Maya version " 00222 << (MAYA_API_VERSION / 100) << "." << (MAYA_API_VERSION / 10) % 10 00223 << ", but you are now running it with Maya version " 00224 << simple_runtime_version 00225 << ". The program may crash or produce incorrect results.\n\n"; 00226 } 00227 } 00228 00229 return _global_api; 00230 } 00231 00232 //////////////////////////////////////////////////////////////////// 00233 // Function: MayaApi::is_valid 00234 // Access: Public 00235 // Description: Returns true if the API has been successfully opened 00236 // and may be used, or false if there is some problem. 00237 //////////////////////////////////////////////////////////////////// 00238 bool MayaApi:: 00239 is_valid() const { 00240 return _is_valid; 00241 } 00242 00243 #ifdef WIN32 00244 static string 00245 back_to_front_slash(const string &str) { 00246 string result = str; 00247 string::iterator si; 00248 for (si = result.begin(); si != result.end(); ++si) { 00249 if ((*si) == '\\') { 00250 (*si) = '/'; 00251 } 00252 } 00253 00254 return result; 00255 } 00256 #endif // WIN32 00257 00258 //////////////////////////////////////////////////////////////////// 00259 // Function: MayaApi::read 00260 // Access: Public 00261 // Description: Reads the indicated maya file into the global model 00262 // space. Returns true if successful, false otherwise. 00263 //////////////////////////////////////////////////////////////////// 00264 bool MayaApi:: 00265 read(const Filename &filename) { 00266 MFileIO::newFile(true); 00267 00268 maya_cat.info() << "Reading " << filename << "\n"; 00269 00270 // Load the file into Maya. Maya seems to want forward slashes, 00271 // even on Windows. 00272 string os_filename = filename.to_os_generic(); 00273 00274 string dirname = _cwd.to_os_specific(); 00275 if (maya_cat.is_debug()) { 00276 maya_cat.debug() << "cwd(read:before): " << dirname.c_str() << endl; 00277 } 00278 00279 MFileIO::newFile(true); 00280 MStatus stat = MFileIO::open(os_filename.c_str()); 00281 // Beginning with Maya2008, the call to read seem to change 00282 // the current directory specially if there is a refrence file! Yikes! 00283 00284 // Furthermore, the current directory may change during the call to 00285 // any Maya function! Egad! 00286 if (chdir(dirname.c_str()) < 0) { 00287 maya_cat.warning() 00288 << "Unable to restore current directory after ::read to " << _cwd 00289 << " after initializing Maya.\n"; 00290 } else { 00291 if (maya_cat.is_debug()) { 00292 maya_cat.debug() 00293 << "Restored current directory after ::read to " << _cwd << "\n"; 00294 } 00295 } 00296 if (!stat) { 00297 stat.perror(os_filename.c_str()); 00298 return false; 00299 } 00300 return true; 00301 } 00302 00303 //////////////////////////////////////////////////////////////////// 00304 // Function: MayaApi::write 00305 // Access: Public 00306 // Description: Writes the global model space to the indicated file. 00307 // Returns true if successful, false otherwise. 00308 //////////////////////////////////////////////////////////////////// 00309 bool MayaApi:: 00310 write(const Filename &filename) { 00311 maya_cat.info() << "Writing " << filename << "\n"; 00312 string os_filename = filename.to_os_generic(); 00313 00314 string dirname = _cwd.to_os_specific(); 00315 if (maya_cat.is_debug()) { 00316 maya_cat.debug() << "cwd(write:before): " << dirname.c_str() << endl; 00317 } 00318 00319 const char *type = "mayaBinary"; 00320 string extension = filename.get_extension(); 00321 if (extension == "ma") { 00322 type = "mayaAscii"; 00323 } 00324 00325 MStatus stat = MFileIO::saveAs(os_filename.c_str(), type, true); 00326 if (!stat) { 00327 stat.perror(os_filename.c_str()); 00328 return false; 00329 } 00330 // Beginning with Maya2008, the call to read seem to change 00331 // the current directory specially if there is a refrence file! Yikes! 00332 00333 // Furthermore, the current directory may change during the call to 00334 // any Maya function! Egad! 00335 if (chdir(dirname.c_str()) < 0) { 00336 maya_cat.warning() 00337 << "Unable to restore current directory after ::write to " << _cwd 00338 << " after initializing Maya.\n"; 00339 } else { 00340 if (maya_cat.is_debug()) { 00341 maya_cat.debug() 00342 << "Restored current directory after ::write to " << _cwd << "\n"; 00343 } 00344 } 00345 return true; 00346 } 00347 00348 //////////////////////////////////////////////////////////////////// 00349 // Function: MayaApi::clear 00350 // Access: Public 00351 // Description: Resets the global model space to the empty state, for 00352 // instance in preparation for building a new file. 00353 // Returns true if successful, false otherwise. 00354 //////////////////////////////////////////////////////////////////// 00355 bool MayaApi:: 00356 clear() { 00357 MStatus stat = MFileIO::newFile(true); 00358 if (!stat) { 00359 stat.perror("clear"); 00360 return false; 00361 } 00362 return true; 00363 } 00364 00365 //////////////////////////////////////////////////////////////////// 00366 // Function: MayaApi::get_units 00367 // Access: Public 00368 // Description: Returns Maya's internal units in effect. 00369 //////////////////////////////////////////////////////////////////// 00370 DistanceUnit MayaApi:: 00371 get_units() { 00372 switch (MDistance::internalUnit()) { 00373 case MDistance::kInches: 00374 return DU_inches; 00375 case MDistance::kFeet: 00376 return DU_feet; 00377 case MDistance::kYards: 00378 return DU_yards; 00379 case MDistance::kMiles: 00380 return DU_statute_miles; 00381 case MDistance::kMillimeters: 00382 return DU_millimeters; 00383 case MDistance::kCentimeters: 00384 return DU_centimeters; 00385 case MDistance::kKilometers: 00386 return DU_kilometers; 00387 case MDistance::kMeters: 00388 return DU_meters; 00389 00390 default: 00391 return DU_invalid; 00392 } 00393 } 00394 00395 //////////////////////////////////////////////////////////////////// 00396 // Function: MayaApi::set_units 00397 // Access: Public 00398 // Description: Set Maya's UI units. 00399 //////////////////////////////////////////////////////////////////// 00400 void MayaApi:: 00401 set_units(DistanceUnit unit) { 00402 switch (unit) { 00403 case DU_inches: 00404 MDistance::setUIUnit(MDistance::kInches); 00405 break; 00406 case DU_feet: 00407 MDistance::setUIUnit(MDistance::kFeet); 00408 break; 00409 case DU_yards: 00410 MDistance::setUIUnit(MDistance::kYards); 00411 break; 00412 case DU_statute_miles: 00413 MDistance::setUIUnit(MDistance::kMiles); 00414 break; 00415 case DU_millimeters: 00416 MDistance::setUIUnit(MDistance::kMillimeters); 00417 break; 00418 case DU_centimeters: 00419 MDistance::setUIUnit(MDistance::kCentimeters); 00420 break; 00421 case DU_kilometers: 00422 MDistance::setUIUnit(MDistance::kKilometers); 00423 break; 00424 case DU_meters: 00425 MDistance::setUIUnit(MDistance::kMeters); 00426 break; 00427 00428 default: 00429 ; 00430 } 00431 } 00432 00433 //////////////////////////////////////////////////////////////////// 00434 // Function: MayaApi::get_coordinate_system 00435 // Access: Public 00436 // Description: Returns Maya's internal coordinate system in effect. 00437 //////////////////////////////////////////////////////////////////// 00438 CoordinateSystem MayaApi:: 00439 get_coordinate_system() { 00440 if (MGlobal::isYAxisUp()) { 00441 return CS_yup_right; 00442 } else { 00443 return CS_zup_right; 00444 } 00445 }