Panda3D
 All Classes Functions Variables Enumerations
mayaApi.cxx
1 // Filename: mayaApi.cxx
2 // Created by: drose (15Apr02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "mayaApi.h"
16 #include "config_maya.h"
17 #include "string_utils.h"
18 #include "thread.h"
19 
20 #include "pre_maya_include.h"
21 #include <maya/MGlobal.h>
22 #include <maya/MDistance.h>
23 #include <maya/MFileIO.h>
24 #include <maya/MLibrary.h>
25 #include <maya/MStatus.h>
26 #include <maya/MFnAnimCurve.h>
27 #include "post_maya_include.h"
28 
29 #ifdef WIN32_VC
30 #include <direct.h> // for chdir()
31 #endif
32 
33 MayaApi *MayaApi::_global_api = (MayaApi *)NULL;
34 
35 // We need this bogus object just to force the application to link
36 // with OpenMayaAnim.lib; otherwise, Maya will complain (when compiled
37 // on Windows) that it is unable to find source plug 'ikRPsolver.msg'.
38 static MFnAnimCurve force_link_with_OpenMayaAnim;
39 
40 ////////////////////////////////////////////////////////////////////
41 // Function: MayaApi::Constructor
42 // Access: Protected
43 // Description: Don't attempt to create this object directly;
44 // instead, use the open_api() method.
45 ////////////////////////////////////////////////////////////////////
46 MayaApi::
47 MayaApi(const string &program_name, bool view_license, bool revert_dir) {
48  if (program_name == "plug-in") {
49  // In this special case, we are invoking the code from within a
50  // plug-in, so we need not (and should not) call
51  // MLibrary::initialize().
52  _plug_in = true;
53  _is_valid = true;
54  return;
55  }
56 
57  // Otherwise, if program_name is any other name, we are invoking the
58  // code from a standalone application and we do need to call
59  // MLibrary::initialize().
60  _plug_in = false;
61 
62  // Beginning with Maya4.5, the call to initialize seems to change
63  // the current directory! Yikes!
64 
65  // Furthermore, the current directory may change during the call to
66  // any Maya function! Egad!
68  MStatus stat = MLibrary::initialize(false, (char *)program_name.c_str(), view_license);
69 
70  int error_count = init_maya_repeat_count;
71  while (!stat && error_count > 1) {
72  stat.perror("MLibrary::initialize");
73  Thread::sleep(init_maya_timeout);
74  stat = MLibrary::initialize(false, (char *)program_name.c_str(), view_license);
75  --error_count;
76  }
77 
78  // Restore the current directory. Ever since Maya 2010, there seems to be
79  // some bad mojo when you do this.
80  if( revert_dir ){
81  string dirname = _cwd.to_os_specific();
82  if (chdir(dirname.c_str()) < 0) {
83  maya_cat.warning()
84  << "Unable to restore current directory to " << _cwd
85  << " after initializing Maya.\n";
86  } else {
87  if (maya_cat.is_debug()) {
88  maya_cat.debug()
89  << "Restored current directory to " << _cwd << "\n";
90  }
91  }
92  }
93 
94 
95  if (!stat) {
96  stat.perror("MLibrary::initialize");
97  _is_valid = false;
98  } else {
99  _is_valid = true;
100  }
101 }
102 
103 ////////////////////////////////////////////////////////////////////
104 // Function: MayaApi::Copy Constructor
105 // Access: Protected
106 // Description: Don't attempt to copy MayaApi objects. There should
107 // be only one of these in the world at a time.
108 ////////////////////////////////////////////////////////////////////
109 MayaApi::
110 MayaApi(const MayaApi &copy) {
111  nassertv(false);
112 }
113 
114 ////////////////////////////////////////////////////////////////////
115 // Function: MayaApi::Copy Assignment Operator
116 // Access: Protected
117 // Description: Don't attempt to copy MayaApi objects. There should
118 // be only one of these in the world at a time.
119 ////////////////////////////////////////////////////////////////////
120 void MayaApi::
121 operator = (const MayaApi &copy) {
122  nassertv(false);
123 }
124 
125 ////////////////////////////////////////////////////////////////////
126 // Function: MayaApi::Destructor
127 // Access: Public
128 // Description:
129 ////////////////////////////////////////////////////////////////////
130 MayaApi::
131 ~MayaApi() {
132  nassertv(_global_api == this);
133  if (_is_valid && !_plug_in) {
134  // Caution! Calling this function seems to call exit() somewhere
135  // within Maya code.
136  MLibrary::cleanup();
137  }
138  _global_api = (MayaApi *)NULL;
139 }
140 
141 ////////////////////////////////////////////////////////////////////
142 // Function: MayaApi::open_api
143 // Access: Public, Static
144 // Description: Opens the Maya API, if it is not already open, and
145 // returns a pointer representing this connection. When
146 // you are done using the Maya API, let the pointer
147 // destruct.
148 //
149 // If program_name is supplied, it is passed to Maya as
150 // the name of the currently-executing program.
151 // Otherwise, the current program name is extracted from
152 // the execution environment, if possible. The special
153 // program_name "plug-in" is used for code that is
154 // intended to be invoked as a plug-in only; in this
155 // case, the maya library is not re-initialized.
156 ////////////////////////////////////////////////////////////////////
157 PT(MayaApi) MayaApi::
158 open_api(string program_name, bool view_license, bool revertdir) {
159  if (_global_api == (MayaApi *)NULL) {
160  // We need to create a new MayaApi object.
161  if (program_name.empty()) {
162  program_name = ExecutionEnvironment::get_binary_name();
163  if (program_name.empty()) {
164  program_name = "Panda";
165  }
166  }
167 
168  _global_api = new MayaApi(program_name, view_license, revertdir);
169 
170  // Try to compare the string-formatted runtime version number with
171  // the numeric compile-time version number, so we can sanity check
172  // our runtime environment. (Sure would be nice if Maya provided
173  // an apples-to-apples comparison for us.)
174 
175  // According to the Maya specs, the numeric value is derived by
176  // taking the Maya version number and deleting the '.' characters,
177  // while also ignoring everything after the second dot (and, for
178  // some reason, appending a 0).
179 
180  string runtime_version = MGlobal::mayaVersion().asChar();
181  string simple_runtime_version = runtime_version;
182  runtime_version = trim(runtime_version);
183 
184  // If the version number contains a space, stop there (that would
185  // be "service pack 1" or whatever).
186  size_t space = runtime_version.find(' ');
187  if (space != string::npos) {
188  runtime_version = runtime_version.substr(0, space);
189  }
190 
191  int rtver_a, rtver_b;
192  size_t dot1 = runtime_version.find('.');
193  if (dot1 == string::npos) {
194  string_to_int(runtime_version, rtver_a);
195  rtver_b = 0;
196 
197  } else {
198  string_to_int(runtime_version.substr(0, dot1), rtver_a);
199 
200  size_t dot2 = runtime_version.find('.', dot1 + 1);
201  if (dot2 == string::npos) {
202  rtver_b = 0;
203  } else {
204  string_to_int(runtime_version.substr(dot1, dot2 - dot1), rtver_b);
205  simple_runtime_version = runtime_version.substr(0, dot2);
206  }
207  }
208 
209  int runtime_version_int = rtver_a * 100 + rtver_b * 10;
210 
211  if (maya_cat.is_debug()) {
212  maya_cat.debug()
213  << "Compiled with Maya library version "
214  << (MAYA_API_VERSION / 100) << "." << (MAYA_API_VERSION / 10) % 10
215  << " (" << MAYA_API_VERSION << "); running with library version "
216  << runtime_version << ".\n";
217  }
218 
219  if (MAYA_API_VERSION / 10 != runtime_version_int / 10) {
220  maya_cat.warning()
221  << "This program was compiled using Maya version "
222  << (MAYA_API_VERSION / 100) << "." << (MAYA_API_VERSION / 10) % 10
223  << ", but you are now running it with Maya version "
224  << simple_runtime_version
225  << ". The program may crash or produce incorrect results.\n\n";
226  }
227  }
228 
229  return _global_api;
230 }
231 
232 ////////////////////////////////////////////////////////////////////
233 // Function: MayaApi::is_valid
234 // Access: Public
235 // Description: Returns true if the API has been successfully opened
236 // and may be used, or false if there is some problem.
237 ////////////////////////////////////////////////////////////////////
238 bool MayaApi::
239 is_valid() const {
240  return _is_valid;
241 }
242 
243 #ifdef WIN32
244 static string
245 back_to_front_slash(const string &str) {
246  string result = str;
247  string::iterator si;
248  for (si = result.begin(); si != result.end(); ++si) {
249  if ((*si) == '\\') {
250  (*si) = '/';
251  }
252  }
253 
254  return result;
255 }
256 #endif // WIN32
257 
258 ////////////////////////////////////////////////////////////////////
259 // Function: MayaApi::read
260 // Access: Public
261 // Description: Reads the indicated maya file into the global model
262 // space. Returns true if successful, false otherwise.
263 ////////////////////////////////////////////////////////////////////
264 bool MayaApi::
265 read(const Filename &filename) {
266  MFileIO::newFile(true);
267 
268  maya_cat.info() << "Reading " << filename << "\n";
269 
270  // Load the file into Maya. Maya seems to want forward slashes,
271  // even on Windows.
272  string os_filename = filename.to_os_generic();
273 
274  string dirname = _cwd.to_os_specific();
275  if (maya_cat.is_debug()) {
276  maya_cat.debug() << "cwd(read:before): " << dirname.c_str() << endl;
277  }
278 
279  MFileIO::newFile(true);
280  MStatus stat = MFileIO::open(os_filename.c_str());
281  // Beginning with Maya2008, the call to read seem to change
282  // the current directory specially if there is a refrence file! Yikes!
283 
284  // Furthermore, the current directory may change during the call to
285  // any Maya function! Egad!
286  if (chdir(dirname.c_str()) < 0) {
287  maya_cat.warning()
288  << "Unable to restore current directory after ::read to " << _cwd
289  << " after initializing Maya.\n";
290  } else {
291  if (maya_cat.is_debug()) {
292  maya_cat.debug()
293  << "Restored current directory after ::read to " << _cwd << "\n";
294  }
295  }
296  if (!stat) {
297  stat.perror(os_filename.c_str());
298  return false;
299  }
300  return true;
301 }
302 
303 ////////////////////////////////////////////////////////////////////
304 // Function: MayaApi::write
305 // Access: Public
306 // Description: Writes the global model space to the indicated file.
307 // Returns true if successful, false otherwise.
308 ////////////////////////////////////////////////////////////////////
309 bool MayaApi::
310 write(const Filename &filename) {
311  maya_cat.info() << "Writing " << filename << "\n";
312  string os_filename = filename.to_os_generic();
313 
314  string dirname = _cwd.to_os_specific();
315  if (maya_cat.is_debug()) {
316  maya_cat.debug() << "cwd(write:before): " << dirname.c_str() << endl;
317  }
318 
319  const char *type = "mayaBinary";
320  string extension = filename.get_extension();
321  if (extension == "ma") {
322  type = "mayaAscii";
323  }
324 
325  MStatus stat = MFileIO::saveAs(os_filename.c_str(), type, true);
326  if (!stat) {
327  stat.perror(os_filename.c_str());
328  return false;
329  }
330  // Beginning with Maya2008, the call to read seem to change
331  // the current directory specially if there is a refrence file! Yikes!
332 
333  // Furthermore, the current directory may change during the call to
334  // any Maya function! Egad!
335  if (chdir(dirname.c_str()) < 0) {
336  maya_cat.warning()
337  << "Unable to restore current directory after ::write to " << _cwd
338  << " after initializing Maya.\n";
339  } else {
340  if (maya_cat.is_debug()) {
341  maya_cat.debug()
342  << "Restored current directory after ::write to " << _cwd << "\n";
343  }
344  }
345  return true;
346 }
347 
348 ////////////////////////////////////////////////////////////////////
349 // Function: MayaApi::clear
350 // Access: Public
351 // Description: Resets the global model space to the empty state, for
352 // instance in preparation for building a new file.
353 // Returns true if successful, false otherwise.
354 ////////////////////////////////////////////////////////////////////
355 bool MayaApi::
356 clear() {
357  MStatus stat = MFileIO::newFile(true);
358  if (!stat) {
359  stat.perror("clear");
360  return false;
361  }
362  return true;
363 }
364 
365 ////////////////////////////////////////////////////////////////////
366 // Function: MayaApi::get_units
367 // Access: Public
368 // Description: Returns Maya's internal units in effect.
369 ////////////////////////////////////////////////////////////////////
370 DistanceUnit MayaApi::
372  switch (MDistance::internalUnit()) {
373  case MDistance::kInches:
374  return DU_inches;
375  case MDistance::kFeet:
376  return DU_feet;
377  case MDistance::kYards:
378  return DU_yards;
379  case MDistance::kMiles:
380  return DU_statute_miles;
381  case MDistance::kMillimeters:
382  return DU_millimeters;
383  case MDistance::kCentimeters:
384  return DU_centimeters;
385  case MDistance::kKilometers:
386  return DU_kilometers;
387  case MDistance::kMeters:
388  return DU_meters;
389 
390  default:
391  return DU_invalid;
392  }
393 }
394 
395 ////////////////////////////////////////////////////////////////////
396 // Function: MayaApi::set_units
397 // Access: Public
398 // Description: Set Maya's UI units.
399 ////////////////////////////////////////////////////////////////////
400 void MayaApi::
401 set_units(DistanceUnit unit) {
402  switch (unit) {
403  case DU_inches:
404  MDistance::setUIUnit(MDistance::kInches);
405  break;
406  case DU_feet:
407  MDistance::setUIUnit(MDistance::kFeet);
408  break;
409  case DU_yards:
410  MDistance::setUIUnit(MDistance::kYards);
411  break;
412  case DU_statute_miles:
413  MDistance::setUIUnit(MDistance::kMiles);
414  break;
415  case DU_millimeters:
416  MDistance::setUIUnit(MDistance::kMillimeters);
417  break;
418  case DU_centimeters:
419  MDistance::setUIUnit(MDistance::kCentimeters);
420  break;
421  case DU_kilometers:
422  MDistance::setUIUnit(MDistance::kKilometers);
423  break;
424  case DU_meters:
425  MDistance::setUIUnit(MDistance::kMeters);
426  break;
427 
428  default:
429  ;
430  }
431 }
432 
433 ////////////////////////////////////////////////////////////////////
434 // Function: MayaApi::get_coordinate_system
435 // Access: Public
436 // Description: Returns Maya's internal coordinate system in effect.
437 ////////////////////////////////////////////////////////////////////
438 CoordinateSystem MayaApi::
440  if (MGlobal::isYAxisUp()) {
441  return CS_yup_right;
442  } else {
443  return CS_zup_right;
444  }
445 }
void set_units(DistanceUnit unit)
Set Maya&#39;s UI units.
Definition: mayaApi.cxx:401
bool read(const Filename &filename)
Reads the indicated maya file into the global model space.
Definition: mayaApi.cxx:265
static string get_binary_name()
Returns the name of the binary executable that started this program, if it can be determined...
bool write(const Filename &filename)
Writes the global model space to the indicated file.
Definition: mayaApi.cxx:310
DistanceUnit get_units()
Returns Maya&#39;s internal units in effect.
Definition: mayaApi.cxx:371
bool clear()
Resets the global model space to the empty state, for instance in preparation for building a new file...
Definition: mayaApi.cxx:356
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
bool is_valid() const
Returns true if the API has been successfully opened and may be used, or false if there is some probl...
Definition: mayaApi.cxx:239
string to_os_generic() const
This is similar to to_os_specific(), but it is designed to generate a filename that can be understood...
Definition: filename.cxx:1261
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1196
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
Definition: thread.I:236
static Filename get_cwd()
Returns the name of the current working directory.
CoordinateSystem get_coordinate_system()
Returns Maya&#39;s internal coordinate system in effect.
Definition: mayaApi.cxx:439
string get_extension() const
Returns the file extension.
Definition: filename.I:477
This class presents a wrapper around the global Maya interface.
Definition: mayaApi.h:33