Panda3D
maya_funcs.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 maya_funcs.cxx
10 * @author drose
11 * @date 2000-02-16
12 */
13
14#include "maya_funcs.h"
15
16#include "pre_maya_include.h"
17#include <maya/MObject.h>
18#include <maya/MAngle.h>
19#include <maya/MFnDependencyNode.h>
20#include <maya/MStatus.h>
21#include <maya/MFnStringData.h>
22#include <maya/MFnNumericData.h>
23#include <maya/MPlugArray.h>
24#include <maya/MPlug.h>
25#include <maya/MFnAttribute.h>
26#include <maya/MFnTypedAttribute.h>
27#include <maya/MFnNumericAttribute.h>
28#include <maya/MFnEnumAttribute.h>
29#include <maya/MFnCompoundAttribute.h>
30#include <maya/MFnMatrixData.h>
31#include <maya/MMatrix.h>
32#include "post_maya_include.h"
33
34using std::endl;
35using std::string;
36
37/**
38 * Gets the named MPlug associated, if any.
39 */
40bool
41get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug) {
42 MStatus status;
43 MFnDependencyNode node_fn(node, &status);
44 if (!status) {
45 maya_cat.error()
46 << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
47 return false;
48 }
49
50 MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
51 if (!status) {
52 return false;
53 }
54
55 MFnAttribute attr_fn(attr, &status);
56 if (!status) {
57 maya_cat.error()
58 << "Attribute " << attribute_name << " on " << node_fn.name().asChar()
59 << " is a " << attr.apiTypeStr() << ", not an Attribute.\n";
60 return false;
61 }
62
63 plug = MPlug(node, attr);
64 return true;
65}
66
67/**
68 * Returns true if the named connection exists on the node and is connected to
69 * anything, false otherwise.
70 */
71bool
72is_connected(MObject &node, const string &attribute_name) {
73 MPlug plug;
74 if (!get_maya_plug(node, attribute_name, plug)) {
75 return false;
76 }
77
78 return plug.isConnected();
79}
80
81/**
82 * Returns true if the node has the indicated attribute, false otherwise.
83 */
84bool
85has_attribute(MObject &node, const string &attribute_name) {
86 MStatus status;
87 MFnDependencyNode node_fn(node, &status);
88 if (!status) {
89 maya_cat.error()
90 << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
91 return false;
92 }
93
94 node_fn.attribute(attribute_name.c_str(), &status);
95 if (!status) {
96 // No such attribute.
97 return false;
98 }
99 return true;
100}
101
102/**
103 * Removes the named attribute from the indicated Maya node. Returns true if
104 * successful, false otherwise.
105 */
106bool
107remove_attribute(MObject &node, const string &attribute_name) {
108 MStatus status;
109 MFnDependencyNode node_fn(node, &status);
110 if (!status) {
111 maya_cat.error()
112 << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
113 return false;
114 }
115
116 MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
117 if (!status) {
118 return false;
119 }
120
121 {
122 // Just to prove the the attr is, in fact, an Attribute. According to the
123 // Maya docs, we shouldn't leave the MFnAttribute object around while we
124 // remove the attribute, though.
125 MFnAttribute attr_fn(attr, &status);
126 if (!status) {
127 maya_cat.error()
128 << "Attribute " << attribute_name << " on " << node_fn.name().asChar()
129 << " is a " << attr.apiTypeStr() << ", not an Attribute.\n";
130 return false;
131 }
132 }
133
134 MFnDependencyNode::MAttrClass type = node_fn.attributeClass(attr, &status);
135 if (!status) {
136 maya_cat.error()
137 << "Couldn't get class of attribute " << attribute_name << " on "
138 << node_fn.name().asChar() << ".\n";
139 return false;
140 }
141
142 status = node_fn.removeAttribute(attr, type);
143 if (!status) {
144 maya_cat.error()
145 << "Couldn't remove attribute " << attribute_name << " from "
146 << node_fn.name().asChar() << ".\n";
147 return false;
148 }
149
150 return true;
151}
152
153/**
154 * Extracts the named boolean attribute from the MObject.
155 */
156bool
157get_bool_attribute(MObject &node, const string &attribute_name,
158 bool &value) {
159 if (!has_attribute(node, attribute_name)) {
160 // For bool attributes only, we assume if the attribute is absent it's the
161 // same thing as being false.
162 return false;
163 }
164
165 if (!get_maya_attribute(node, attribute_name, value)) {
166 maya_cat.warning()
167 << "Attribute " << attribute_name
168 << " does not have a bool value.\n";
169 describe_maya_attribute(node, attribute_name);
170 return false;
171 }
172 return true;
173}
174
175/**
176 * Extracts the named angle in degrees from the MObject.
177 */
178bool
179get_angle_attribute(MObject &node, const string &attribute_name,
180 double &value) {
181 MAngle maya_value;
182 if (!get_maya_attribute(node, attribute_name, maya_value)) {
183 maya_cat.warning()
184 << "Attribute " << attribute_name
185 << " does not have an angle value.\n";
186 describe_maya_attribute(node, attribute_name);
187 return false;
188 }
189 value = maya_value.asDegrees();
190 return true;
191}
192
193/**
194 * Extracts the named two-component vector from the MObject.
195 */
196bool
197get_vec2_attribute(MObject &node, const string &attribute_name,
198 LVecBase2 &value) {
199 MStatus status;
200
201 MObject vec2_object;
202 if (!get_maya_attribute(node, attribute_name, vec2_object)) {
203 maya_cat.warning()
204 << "Attribute " << attribute_name
205 << " does not have a vec2 object value.\n";
206 describe_maya_attribute(node, attribute_name);
207 return false;
208 }
209
210 MFnNumericData data(vec2_object, &status);
211 if (!status) {
212 maya_cat.warning()
213 << "Attribute " << attribute_name << " is of type "
214 << vec2_object.apiTypeStr() << ", not a NumericData.\n";
215 return false;
216 }
217
218 status = data.getData(value[0], value[1]);
219 if (!status) {
220 maya_cat.warning()
221 << "Unable to extract 2 floats from " << attribute_name
222 << ", of type " << vec2_object.apiTypeStr() << "\n";
223 }
224
225 return true;
226}
227
228/**
229 * Extracts the named three-component vector from the MObject.
230 */
231bool
232get_vec3_attribute(MObject &node, const string &attribute_name,
233 LVecBase3 &value) {
234 MStatus status;
235
236 MObject vec3_object;
237 if (!get_maya_attribute(node, attribute_name, vec3_object)) {
238 maya_cat.warning()
239 << "Attribute " << attribute_name
240 << " does not have a vec3 object value.\n";
241 describe_maya_attribute(node, attribute_name);
242 return false;
243 }
244
245 MFnNumericData data(vec3_object, &status);
246 if (!status) {
247 maya_cat.warning()
248 << "Attribute " << attribute_name << " is of type "
249 << vec3_object.apiTypeStr() << ", not a NumericData.\n";
250 return false;
251 }
252
253 status = data.getData(value[0], value[1], value[2]);
254 if (!status) {
255 maya_cat.warning()
256 << "Unable to extract 3 floats from " << attribute_name
257 << ", of type " << vec3_object.apiTypeStr() << "\n";
258 }
259
260 return true;
261}
262
263/**
264 * Extracts the named two-component vector from the MObject.
265 */
266bool
267get_vec2d_attribute(MObject &node, const string &attribute_name,
268 LVecBase2d &value) {
269 MStatus status;
270
271 MObject vec2d_object;
272 if (!get_maya_attribute(node, attribute_name, vec2d_object)) {
273 maya_cat.warning()
274 << "Attribute " << attribute_name
275 << " does not have a vec2d object value.\n";
276 describe_maya_attribute(node, attribute_name);
277 return false;
278 }
279
280 MFnNumericData data(vec2d_object, &status);
281 if (!status) {
282 maya_cat.warning()
283 << "Attribute " << attribute_name << " is of type "
284 << vec2d_object.apiTypeStr() << ", not a NumericData.\n";
285 return false;
286 }
287
288 status = data.getData(value[0], value[1]);
289 if (!status) {
290 maya_cat.warning()
291 << "Unable to extract 2 doubles from " << attribute_name
292 << ", of type " << vec2d_object.apiTypeStr() << "\n";
293 }
294
295 return true;
296}
297
298/**
299 * Extracts the named three-component vector from the MObject.
300 */
301bool
302get_vec3d_attribute(MObject &node, const string &attribute_name,
303 LVecBase3d &value) {
304 MStatus status;
305
306 MObject vec3d_object;
307 if (!get_maya_attribute(node, attribute_name, vec3d_object)) {
308 maya_cat.warning()
309 << "Attribute " << attribute_name
310 << " does not have a vec3d object value.\n";
311 describe_maya_attribute(node, attribute_name);
312 return false;
313 }
314
315 MFnNumericData data(vec3d_object, &status);
316 if (!status) {
317 maya_cat.warning()
318 << "Attribute " << attribute_name << " is of type "
319 << vec3d_object.apiTypeStr() << ", not a NumericData.\n";
320 return false;
321 }
322
323 status = data.getData(value[0], value[1], value[2]);
324 if (!status) {
325 maya_cat.warning()
326 << "Unable to extract 3 doubles from " << attribute_name
327 << ", of type " << vec3d_object.apiTypeStr() << "\n";
328 }
329
330 return true;
331}
332
333/**
334 * Extracts the named 4x4 matrix from the MObject.
335 */
336bool
337get_mat4d_attribute(MObject &node, const string &attribute_name,
338 LMatrix4d &value) {
339 MStatus status;
340 MObject matrix;
341 if (!get_maya_attribute(node, attribute_name, matrix)) {
342 return false;
343 }
344
345 MFnMatrixData matrix_data(matrix, &status);
346 if (!status) {
347 maya_cat.warning()
348 << "Attribute " << attribute_name << " is of type "
349 << node.apiTypeStr() << ", not a Matrix.\n";
350 return false;
351 }
352
353 const MMatrix &mat = matrix_data.matrix();
354 for (int i = 0; i < 4; i++) {
355 for (int j = 0; j < 4; j++) {
356 value(i, j) = mat(i, j);
357 }
358 }
359 return true;
360}
361
362/**
363 * artists should be able to set arbitrary tags. Query all the attributes on
364 * this object and return the lists of attribute names that has "tag" prefix
365 */
366void
367get_tag_attribute_names(MObject &node, pvector<string> &tag_names) {
368 MStatus status;
369 MFnDependencyNode node_fn(node, &status);
370 if (!status) {
371 maya_cat.warning()
372 << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
373 return;
374 }
375
376 string name = node_fn.name().asChar();
377 unsigned i;
378
379 for (i = 0; i < node_fn.attributeCount(); i++) {
380 MObject attr = node_fn.attribute(i, &status);
381 if (status) {
382 MFnAttribute attrib(attr, &status);
383 if (status) {
384 string attribute_name = attrib.name().asChar();
385 if (attribute_name.find("tag", 0) != string::npos) {
386 maya_cat.info() << ":" << name << ":" << " is tagged with <"
387 << attribute_name << ">" << endl;
388 tag_names.push_back(attribute_name);
389 }
390 }
391 }
392 }
393}
394/**
395 * Extracts the enum attribute from the MObject as a string value.
396 */
397bool
398get_enum_attribute(MObject &node, const string &attribute_name,
399 string &value) {
400 MStatus status;
401
402 MPlug plug;
403 if (!get_maya_plug(node, attribute_name.c_str(), plug)) {
404 return false;
405 }
406
407 MObject attrib = plug.attribute();
408 MFnEnumAttribute enum_attrib(attrib, &status);
409 if (!status) {
410 maya_cat.warning()
411 << "Not an enum attribute: " << attribute_name << "\n";
412 return false;
413 }
414
415 short index;
416 status = plug.getValue(index);
417 if (!status) {
418 maya_cat.warning()
419 << "Could not get numeric value of " << attribute_name << "\n";
420 status.perror("MPlug::getValue(short)");
421 return false;
422 }
423
424 MString name = enum_attrib.fieldName(index, &status);
425 if (!status) {
426 maya_cat.warning()
427 << "Invalid value for " << attribute_name << ": " << index << "\n";
428 status.perror("MFnEnumAttribute::fieldName()");
429 return false;
430 }
431
432 value = name.asChar();
433 return true;
434}
435
436/**
437 * Extracts the named string attribute from the MObject.
438 */
439bool
440get_string_attribute(MObject &node, const string &attribute_name,
441 string &value) {
442 MStatus status;
443
444 MObject string_object;
445 if (!get_maya_attribute(node, attribute_name, string_object)) {
446 maya_cat.warning()
447 << "Attribute " << attribute_name
448 << " does not have an string object value.\n";
449 describe_maya_attribute(node, attribute_name);
450 return false;
451 }
452
453 MFnStringData data(string_object, &status);
454 if (!status) {
455 maya_cat.warning()
456 << "Attribute " << attribute_name << " is of type "
457 << string_object.apiTypeStr() << ", not a StringData.\n";
458 return false;
459 }
460
461 value = data.string().asChar();
462 return true;
463}
464
465/**
466 * Sets the named string attribute on the MObject.
467 */
468bool
469set_string_attribute(MObject &node, const string &attribute_name,
470 const string &value) {
471 MStatus status;
472
473 // First, we get the string_object, then we set its string.
474 MObject string_object;
475 if (!get_maya_attribute(node, attribute_name, string_object)) {
476 maya_cat.warning()
477 << "Attribute " << attribute_name
478 << " does not have a string object value.\n";
479 describe_maya_attribute(node, attribute_name);
480 return false;
481 }
482
483 MFnStringData data(string_object, &status);
484 if (!status) {
485 maya_cat.warning()
486 << "Attribute " << attribute_name << " is of type "
487 << string_object.apiTypeStr() << ", not a StringData.\n";
488 return false;
489 }
490
491 MString mstring_value(value.data(), value.length());
492 status = data.set(mstring_value);
493 if (!status) {
494 status.perror(attribute_name.c_str());
495 return false;
496 }
497
498 // And it appears we now need to set the string object back.
499 if (!set_maya_attribute(node, attribute_name, string_object)) {
500 maya_cat.warning()
501 << "Attribute " << attribute_name
502 << " suddenly does not have a string object value.\n";
503 return false;
504 }
505
506 return true;
507}
508
509/**
510 * Extracts the children of this attribute from the MObject. test for now
511 */
512bool
514 MStatus status;
515
516 MFnCompoundAttribute comp_attr(node, &status);
517
518 maya_cat.info() << "comp_attr has:" << comp_attr.numChildren() << " children" << endl;
519 for (size_t i = 0; i < comp_attr.numChildren(); i++) {
520 MObject child = comp_attr.child(i, &status);
521 if (child.apiType() == MFn::kAttribute3Float){
522 /*
523 LRGBColor color;
524 if (get_vec3_attribute(child, "color", color)) {
525 maya_cat.info() << "color: " << color << endl;
526 }
527 */
528 }
529 else if (child.apiType() == MFn::kNumericAttribute) {
530 MFnNumericAttribute numeric(child, &status);
531 if (status) {
532 switch(numeric.unitType()) {
533 case MFnNumericData::kFloat :
534 PN_stdfloat alpha;
535 status = numeric.getDefault(alpha);
536 maya_cat.info() << "found a float :" << alpha << endl;
537 break;
538 case MFnNumericData::kBoolean :
539 bool v;
540 status = numeric.getDefault(v);
541 maya_cat.info() << "found a bool :" << v << endl;
542 default:
543 maya_cat.info() << numeric.unitType() << endl;
544 }
545 }
546 }
547 else if (child.apiType() == MFn::kEnumAttribute) {
548 MFnEnumAttribute enu(child, &status);
549 if (status) {
550 MString blah;
551 status = enu.getDefault(blah);
552 maya_cat.info() << "found a string :" << blah.asChar() << endl;
553 MPlug plug = MPlug(node, child);
554 maya_cat.info() << "plug name" << plug.name().asChar() << endl;
555 }
556 }
557 }
558 return true;
559}
560
561/**
562 * Writes some warning output about the indicated Maya attribute.
563 */
564void
565describe_maya_attribute(MObject &node, const string &attribute_name) {
566 MStatus status;
567 MFnDependencyNode node_fn(node, &status);
568 if (!status) {
569 maya_cat.warning()
570 << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
571 return;
572 }
573
574 MObject attr = node_fn.attribute(attribute_name.c_str(), &status);
575 if (!status) {
576 maya_cat.warning()
577 << "Object " << node_fn.name().asChar() << " does not support attribute "
578 << attribute_name << "\n";
579 return;
580 }
581
582 maya_cat.warning()
583 << "Attribute " << attribute_name << " on object "
584 << node_fn.name().asChar() << " has type " << attr.apiTypeStr() << "\n";
585}
586
587string
588string_mfndata_type(MFnData::Type type) {
589 switch (type) {
590 case MFnData::kInvalid:
591 return "kInvalid";
592
593 case MFnData::kNumeric:
594 return "kNumeric";
595
596 case MFnData::kPlugin:
597 return "kPlugin";
598
599 case MFnData::kPluginGeometry:
600 return "kPluginGeometry";
601
602 case MFnData::kString:
603 return "kString";
604
605 case MFnData::kMatrix:
606 return "kMatrix";
607
608 case MFnData::kStringArray:
609 return "kStringArray";
610
611 case MFnData::kDoubleArray:
612 return "kDoubleArray";
613
614 case MFnData::kIntArray:
615 return "kIntArray";
616
617 case MFnData::kPointArray:
618 return "kPointArray";
619
620 case MFnData::kVectorArray:
621 return "kVectorArray";
622
623 case MFnData::kComponentList:
624 return "kComponentList";
625
626 case MFnData::kMesh:
627 return "kMesh";
628
629 case MFnData::kLattice:
630 return "kLattice";
631
632 case MFnData::kNurbsCurve:
633 return "kNurbsCurve";
634
635 case MFnData::kNurbsSurface:
636 return "kNurbsSurface";
637
638 case MFnData::kSphere:
639 return "kSphere";
640
641 case MFnData::kDynArrayAttrs:
642 return "kDynArrayAttrs";
643
644 case MFnData::kDynSweptGeometry:
645 return "kDynSweptGeometry";
646
647 case MFnData::kSubdSurface:
648 return "kSubdSurface";
649
650 case MFnData::kLast:
651 default:
652 break;
653 }
654
655 return "**invalid**";
656}
657
658/**
659 * Writes some info output showing all the attributes on the given dependency
660 * node. Primarily useful during development, to figure out where the heck
661 * Maya hides some of the connected properties.
662 */
663void
664list_maya_attributes(MObject &node) {
665 MStatus status;
666 MFnDependencyNode node_fn(node, &status);
667 if (!status) {
668 maya_cat.warning()
669 << "Object is a " << node.apiTypeStr() << ", not a DependencyNode.\n";
670 return;
671 }
672
673 string name = node_fn.name().asChar();
674 unsigned i;
675
676 MPlugArray connections;
677 status = node_fn.getConnections(connections);
678 if (!status) {
679 status.perror("MFnDependencyNode::getConnections");
680
681 } else {
682 maya_cat.info()
683 << name << " has " << connections.length() << " connections.\n";
684 for (i = 0; i < connections.length(); i++) {
685 MPlug plug = connections[i];
686
687 maya_cat.info(false)
688 << " " << i << ". " << plug.name().asChar() << ", "
689 << plug.attribute().apiTypeStr() << ", "
690 << plug.node().apiTypeStr();
691 if (plug.attribute().apiType() == MFn::kCompoundAttribute) {
692 // maya_cat.info() << plug.info();
693 // describe_compound_attribute(plug.attribute());
694 }
695 if (plug.isConnected()) {
696 maya_cat.info(false)
697 << " (*)";
698 }
699 maya_cat.info(false)
700 << "\n";
701 }
702 }
703
704 maya_cat.info()
705 << name << " has " << node_fn.attributeCount() << " attributes.\n";
706 for (i = 0; i < node_fn.attributeCount(); i++) {
707 MObject attr = node_fn.attribute(i, &status);
708 if (status) {
709 MFnTypedAttribute typed_attrib(attr, &status);
710 if (status) {
711 // It's a typed attrib.
712 maya_cat.info(false)
713 << " " << i << ". " << typed_attrib.name().asChar()
714 << " [" << attr.apiTypeStr() << ", "
715 << string_mfndata_type(typed_attrib.attrType()) << "]\n";
716 } else {
717 MFnAttribute attrib(attr, &status);
718 if (status) {
719 // It's a generic attrib.
720 maya_cat.info(false)
721 << " " << i << ". " << attrib.name().asChar()
722 << " [" << attr.apiTypeStr() << "]\n";
723 } else {
724 // Don't know what it is.
725 maya_cat.info(false)
726 << " " << i << ". [" << attr.apiTypeStr() << "]\n";
727 }
728 }
729 }
730 }
731}
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
bool remove_attribute(MObject &node, const string &attribute_name)
Removes the named attribute from the indicated Maya node.
Definition: maya_funcs.cxx:107
bool get_maya_plug(MObject &node, const string &attribute_name, MPlug &plug)
Gets the named MPlug associated, if any.
Definition: maya_funcs.cxx:41
bool get_vec3d_attribute(MObject &node, const string &attribute_name, LVecBase3d &value)
Extracts the named three-component vector from the MObject.
Definition: maya_funcs.cxx:302
bool get_string_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the named string attribute from the MObject.
Definition: maya_funcs.cxx:440
void get_tag_attribute_names(MObject &node, pvector< string > &tag_names)
artists should be able to set arbitrary tags.
Definition: maya_funcs.cxx:367
bool get_angle_attribute(MObject &node, const string &attribute_name, double &value)
Extracts the named angle in degrees from the MObject.
Definition: maya_funcs.cxx:179
bool set_string_attribute(MObject &node, const string &attribute_name, const string &value)
Sets the named string attribute on the MObject.
Definition: maya_funcs.cxx:469
void list_maya_attributes(MObject &node)
Writes some info output showing all the attributes on the given dependency node.
Definition: maya_funcs.cxx:664
bool is_connected(MObject &node, const string &attribute_name)
Returns true if the named connection exists on the node and is connected to anything,...
Definition: maya_funcs.cxx:72
void describe_maya_attribute(MObject &node, const string &attribute_name)
Writes some warning output about the indicated Maya attribute.
Definition: maya_funcs.cxx:565
bool get_vec3_attribute(MObject &node, const string &attribute_name, LVecBase3 &value)
Extracts the named three-component vector from the MObject.
Definition: maya_funcs.cxx:232
bool get_enum_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the enum attribute from the MObject as a string value.
Definition: maya_funcs.cxx:398
bool has_attribute(MObject &node, const string &attribute_name)
Returns true if the node has the indicated attribute, false otherwise.
Definition: maya_funcs.cxx:85
bool get_mat4d_attribute(MObject &node, const string &attribute_name, LMatrix4d &value)
Extracts the named 4x4 matrix from the MObject.
Definition: maya_funcs.cxx:337
bool get_vec2d_attribute(MObject &node, const string &attribute_name, LVecBase2d &value)
Extracts the named two-component vector from the MObject.
Definition: maya_funcs.cxx:267
bool describe_compound_attribute(MObject &node)
Extracts the children of this attribute from the MObject.
Definition: maya_funcs.cxx:513
bool get_vec2_attribute(MObject &node, const string &attribute_name, LVecBase2 &value)
Extracts the named two-component vector from the MObject.
Definition: maya_funcs.cxx:197
bool get_bool_attribute(MObject &node, const string &attribute_name, bool &value)
Extracts the named boolean attribute from the MObject.
Definition: maya_funcs.cxx:157
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.