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
32 using std::string;
33
34 MayaApi *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'.
39 static MFnAnimCurve force_link_with_OpenMayaAnim;
40
41 /**
42 * Don't attempt to create this object directly; instead, use the open_api()
43 * method.
44 */
45 MayaApi::
46 MayaApi(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!
65 _cwd = ExecutionEnvironment::get_cwd();
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 */
105 MayaApi::
106 MayaApi(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 */
114 void MayaApi::
115 operator = (const MayaApi &copy) {
116 nassertv(false);
117 }
118
119 /**
120 *
121 */
122 MayaApi::
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 */
144 PT(MayaApi) MayaApi::
145 open_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()) {
149 program_name = ExecutionEnvironment::get_binary_name();
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 */
224 bool MayaApi::
225 is_valid() const {
226 return _is_valid;
227 }
228
229 #ifdef WIN32
230 static string
231 back_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 */
248 bool MayaApi::
249 read(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 */
291 bool MayaApi::
292 write(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 */
335 bool MayaApi::
336 clear() {
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 */
348 DistanceUnit MayaApi::
349 get_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 */
376 void MayaApi::
377 set_units(DistanceUnit unit) {
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 */
412 CoordinateSystem MayaApi::
413 get_coordinate_system() {
414 if (MGlobal::isYAxisUp()) {
415 return CS_yup_right;
416 } else {
417 return CS_zup_right;
418 }
419 }
ExecutionEnvironment::get_binary_name
get_binary_name
Returns the name of the binary executable that started this program, if it can be determined.
Definition: executionEnvironment.h:59
ExecutionEnvironment::get_cwd
get_cwd
Returns the name of the current working directory.
Definition: executionEnvironment.h:61
Filename
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
Filename::to_os_specific
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
Filename::to_os_generic
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
Filename::get_extension
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
MayaApi
This class presents a wrapper around the global Maya interface.
Definition: mayaApi.h:30
MayaApi::set_units
void set_units(DistanceUnit unit)
Set Maya's UI units.
Definition: mayaApi.cxx:377
MayaApi::get_coordinate_system
CoordinateSystem get_coordinate_system()
Returns Maya's internal coordinate system in effect.
Definition: mayaApi.cxx:413
MayaApi::clear
bool clear()
Resets the global model space to the empty state, for instance in preparation for building a new file...
Definition: mayaApi.cxx:336
MayaApi::get_units
DistanceUnit get_units()
Returns Maya's internal units in effect.
Definition: mayaApi.cxx:349
MayaApi::write
bool write(const Filename &filename)
Writes the global model space to the indicated file.
Definition: mayaApi.cxx:292
MayaApi::read
bool read(const Filename &filename)
Reads the indicated maya file into the global model space.
Definition: mayaApi.cxx:249
Thread::sleep
static void sleep(double seconds)
Suspends the current thread for at least the indicated amount of time.
Definition: thread.I:192
config_maya.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
DistanceUnit
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
PT(MayaApi) MayaApi
Opens the Maya API, if it is not already open, and returns a pointer representing this connection.
Definition: mayaApi.cxx:144
mayaApi.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
post_maya_include.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pre_maya_include.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
trim
string trim(const string &str)
Returns a new string representing the contents of the given string with both leading and trailing whi...
Definition: string_utils.cxx:281
string_to_int
int string_to_int(const string &str, string &tail)
A string-interface wrapper around the C library strtol().
Definition: string_utils.cxx:324
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
thread.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.