Panda3D
Loading...
Searching...
No Matches
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:44
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
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...
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...
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.