Panda3D
 All Classes Functions Variables Enumerations
mayaApi.cxx
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 &copy) {
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 &copy) {
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 }
 All Classes Functions Variables Enumerations