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