Panda3D
Loading...
Searching...
No Matches
mayaNodeTree.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 mayaNodeTree.cxx
10 * @author drose
11 * @date 2003-06-06
12 */
13
14#include "mayaNodeTree.h"
15#include "mayaBlendDesc.h"
17#include "mayaToEggConverter.h"
18#include "config_mayaegg.h"
19#include "maya_funcs.h"
20#include "eggGroup.h"
21#include "eggTable.h"
22#include "eggXfmSAnim.h"
23#include "eggSAnimData.h"
24#include "eggData.h"
25#include "eggSwitchCondition.h"
26#include "dcast.h"
27
28#include "pre_maya_include.h"
29#include <maya/MString.h>
30#include <maya/MItDag.h>
31#include <maya/MSelectionList.h>
32#include <maya/MGlobal.h>
33#include "post_maya_include.h"
34
35#include <sstream>
36
37using std::string;
38
39/**
40 *
41 */
42MayaNodeTree::
43MayaNodeTree(MayaToEggConverter *converter) :
44 _converter(converter)
45{
46 _root = new MayaNodeDesc(this);
47 _fps = 0.0;
48 _egg_data = nullptr;
49 _egg_root = nullptr;
50 _skeleton_node = nullptr;
51 _morph_node = nullptr;
52}
53
54/**
55 * Returns a pointer to the node corresponding to the indicated dag_path
56 * object, creating it first if necessary.
57 */
59build_node(const MDagPath &dag_path) {
60 MayaNodeDesc *node_desc = r_build_node(dag_path.fullPathName().asChar());
61 node_desc->from_dag_path(dag_path, _converter);
62 return node_desc;
63}
64
65/**
66 * Walks through the complete Maya hierarchy but does not tag any nodes for
67 * conversion.
68 */
71 MStatus status;
72
73 MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status);
74 if (!status) {
75 status.perror("MItDag constructor");
76 return false;
77 }
78
79 /*
80 // this is how you can reset the traverser to a specific node
81 status = dag_iterator.reset(dag_iterator.item(),MItDag::kDepthFirst, MFn::kTransform);
82 */
83 // Get the entire Maya scene.
84
85 // This while loop walks through the entire Maya hierarchy, one node at a
86 // time. Maya's MItDag object automatically performs a depth-first
87 // traversal of its scene graph.
88
89 bool all_ok = true;
90 while (!dag_iterator.isDone()) {
91 MDagPath dag_path;
92 status = dag_iterator.getPath(dag_path);
93 if (!status) {
94 status.perror("MItDag::getPath");
95 } else {
96 build_node(dag_path);
97 }
98
99 dag_iterator.next();
100 }
101
102 if (all_ok) {
103 _root->check_pseudo_joints(false);
104 _root->check_lods();
105 }
106
107 return all_ok;
108}
109
110/**
111 * Tags the entire hierarchy for conversion. This is the normal behavior.
112 */
115 _root->tag_joint_recursively();
116}
117
118/**
119 * Tags nodes matching the indicated glob (and all of their children) for
120 * conversion. Returns true on success, false otherwise (e.g. the named node
121 * does not exist).
122 */
124tag_joint_named(const GlobPattern &glob) {
125 // There might be multiple nodes matching the name; search for all of them.
126 bool found_any = false;
127
128 Nodes::iterator ni;
129 for (ni = _nodes.begin(); ni != _nodes.end(); ++ni) {
130 MayaNodeDesc *node = (*ni);
131 if (glob.matches(node->get_name())) {
132 node->tag_joint_recursively();
133 found_any = true;
134 }
135 }
136
137 return found_any;
138}
139
140/**
141 * Tags the entire hierarchy for conversion. This is the normal behavior.
142 */
144tag_all() {
145 _root->tag_recursively();
146}
147
148/**
149 * Tags nodes matching the indicated glob (and all of their children) for
150 * conversion. Returns true on success, false otherwise (e.g. the named node
151 * does not exist).
152 */
154tag_named(const GlobPattern &glob) {
155 // There might be multiple nodes matching the name; search for all of them.
156 bool found_any = false;
157
158 Nodes::iterator ni;
159 for (ni = _nodes.begin(); ni != _nodes.end(); ++ni) {
160 MayaNodeDesc *node = (*ni);
161 if (glob.matches(node->get_name())) {
162 node->tag_recursively();
163 found_any = true;
164 }
165 }
166
167 return found_any;
168}
169
170/**
171 * Un-tags nodes matching the indicated glob (and all of their children) for
172 * conversion. Returns true on success, false otherwise (e.g. the named node
173 * does not exist).
174 */
176untag_named(const GlobPattern &glob) {
177 // There might be multiple nodes matching the name; search for all of them.
178 bool found_any = false;
179
180 Nodes::iterator ni;
181 for (ni = _nodes.begin(); ni != _nodes.end(); ++ni) {
182 MayaNodeDesc *node = (*ni);
183 if (glob.matches(node->get_name())) {
184 node->untag_recursively();
185 found_any = true;
186 }
187 }
188
189 return found_any;
190}
191
192/**
193 * Tags the just the selected hierarchy for conversion, or the entire
194 * hierarchy if nothing is selected. Returns true on success, false on
195 * failure.
196 */
198tag_selected() {
199 MStatus status;
200
201 MItDag dag_iterator(MItDag::kDepthFirst, MFn::kTransform, &status);
202 if (!status) {
203 status.perror("MItDag constructor");
204 return false;
205 }
206
207 MSelectionList selection;
208 status = MGlobal::getActiveSelectionList(selection);
209 if (!status) {
210 status.perror("MGlobal::getActiveSelectionList");
211 return false;
212 }
213
214 if (selection.isEmpty()) {
215 mayaegg_cat.info()
216 << "Selection list is empty.\n";
217 tag_all();
218 return true;
219 }
220
221 bool all_ok = true;
222 unsigned int length = selection.length();
223 for (unsigned int i = 0; i < length; i++) {
224 MDagPath root_path;
225 status = selection.getDagPath(i, root_path);
226 if (!status) {
227 status.perror("MSelectionList::getDagPath");
228 } else {
229 // Now traverse through the selected dag path and all nested dag paths.
230 dag_iterator.reset(root_path);
231 while (!dag_iterator.isDone()) {
232 MDagPath dag_path;
233 status = dag_iterator.getPath(dag_path);
234 if (!status) {
235 status.perror("MItDag::getPath");
236 } else {
237 build_node(dag_path)->tag();
238 }
239
240 dag_iterator.next();
241 }
242 }
243 }
244
245 if (all_ok) {
246 _root->check_pseudo_joints(false);
247 }
248
249 return all_ok;
250}
251
252/**
253 * Returns the total number of nodes in the hierarchy, not counting the root
254 * node.
255 */
257get_num_nodes() const {
258 return _nodes.size();
259}
260
261/**
262 * Returns the nth node in the hierarchy, in an arbitrary ordering.
263 */
265get_node(int n) const {
266 nassertr(n >= 0 && n < (int)_nodes.size(), nullptr);
267 return _nodes[n];
268}
269
270/**
271 * Resets the entire tree in preparation for repopulating with a new scene.
272 */
274clear() {
275 _root = new MayaNodeDesc(this);
276 _fps = 0.0;
277 _egg_data = nullptr;
278 _egg_root = nullptr;
279 _skeleton_node = nullptr;
280 _morph_node = nullptr;
281 _nodes_by_path.clear();
282 _nodes.clear();
283}
284
285/**
286 * Removes all of the references to generated egg structures from the tree,
287 * and prepares the tree for generating new egg structures.
288 */
290clear_egg(EggData *egg_data, EggGroupNode *egg_root,
291 EggGroupNode *skeleton_node, EggGroupNode *morph_node) {
292 _root->clear_egg();
293 BlendDescs::iterator bi;
294 for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) {
295 (*bi)->clear_egg();
296 }
297
298 _egg_data = egg_data;
299 _egg_root = egg_root;
300 _skeleton_node = skeleton_node;
301 _morph_node = morph_node;
302}
303
304/**
305 * Returns the EggGroupNode corresponding to the group or joint for the
306 * indicated node. Creates the group node if it has not already been created.
307 */
309get_egg_group(MayaNodeDesc *node_desc) {
310 nassertr(_egg_root != nullptr, nullptr);
311
312 if (node_desc->_egg_group == nullptr) {
313 // We need to make a new group node.
314 EggGroup *egg_group;
315
316 nassertr(node_desc->_parent != nullptr, nullptr);
317 egg_group = new EggGroup(node_desc->get_name());
318 if (node_desc->is_joint()) {
319 if (_converter->get_animation_convert() == AC_model ||
320 _converter->get_animation_convert() == AC_both) {
321 egg_group->set_group_type(EggGroup::GT_joint);
322 }
323 }
324
325 MayaEggGroupUserData *parent_user_data = nullptr;
326
327 if (node_desc->_parent == _root) {
328 // The parent is the root.
329 _egg_root->add_child(egg_group);
330
331 } else {
332 // The parent is another node.
333 EggGroup *parent_egg_group = get_egg_group(node_desc->_parent);
334 parent_egg_group->add_child(egg_group);
335
336 if (parent_egg_group->has_user_data()) {
337 DCAST_INTO_R(parent_user_data, parent_egg_group->get_user_data(), nullptr);
338 }
339 }
340
341 if (node_desc->has_dag_path()) {
342 // Check for an object type setting, from Oliver's plug-in.
343 MObject dag_object = node_desc->get_dag_path().node();
344 string object_type;
345 LVector3d value;
346
347 for (unsigned int i = 1; ; i++) {
348 std::ostringstream attr;
349 attr << "eggObjectTypes" << i;
350
351 if (!get_enum_attribute(dag_object, attr.str(), object_type)) {
352 if (i < 3) {
353 // Support out-of-order legacy object types.
354 continue;
355 }
356
357 // We have run out of object types to add.
358 break;
359 }
360
361 egg_group->add_object_type(object_type);
362 }
363
364 if(has_attribute(dag_object, "scrollUV")) {
365 if(get_vec3d_attribute(dag_object, "scrollUV", value)) {
366 egg_group->set_scroll_u(value[0]);
367 egg_group->set_scroll_v(value[1]);
368 egg_group->set_scroll_r(value[2]);
369 }
370 }
371
372 pvector<string> tag_attribute_names;
373 get_tag_attribute_names(dag_object, tag_attribute_names);
374 for (uint ti=0; ti < tag_attribute_names.size(); ti++) {
375 if (get_enum_attribute(dag_object, tag_attribute_names[ti], object_type)) {
376 egg_group->set_tag(tag_attribute_names[ti].substr(3), object_type);
377 }
378 }
379
380 // Is the node flagged to be invisible? If it is, it is tagged with the
381 // "hidden" visibility flag, so it won't get converted in the normal
382 // case (unless it represents a collision solid or something).
383 bool visible = true;
384 get_bool_attribute(dag_object, "visibility", visible);
385 if (!visible && egg_group->get_num_object_types() == 0) {
386 egg_group->set_visibility_mode(EggGroup::VM_hidden);
387 }
388
389 // We treat the object type "billboard" as a special case: we apply this
390 // one right away and also flag the group as an instance.
391 if (egg_group->has_object_type("billboard")) {
392 egg_group->remove_object_type("billboard");
393 egg_group->set_group_type(EggGroup::GT_instance);
394 egg_group->set_billboard_type(EggGroup::BT_axis);
395
396 } else if (egg_group->has_object_type("billboard-point")) {
397 egg_group->remove_object_type("billboard-point");
398 egg_group->set_group_type(EggGroup::GT_instance);
399 egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
400
401 } else if (egg_group->has_object_type("bbpoint")) {
402 egg_group->remove_object_type("bbpoint");
403 egg_group->set_group_type(EggGroup::GT_instance);
404 egg_group->set_billboard_type(EggGroup::BT_point_camera_relative);
405 }
406
407 // We also treat the object type "dcs" and "model" as a special case, so
408 // we can test for these flags later.
409 if (egg_group->has_object_type("dcs")) {
410 egg_group->remove_object_type("dcs");
411 egg_group->set_dcs_type(EggGroup::DC_default);
412 }
413 if (egg_group->has_object_type("model")) {
414 egg_group->remove_object_type("model");
415 egg_group->set_model_flag(true);
416 }
417
418 // And "vertex-color" and "double-sided" have meaning only to this
419 // converter.
420 MayaEggGroupUserData *user_data;
421 if (parent_user_data == nullptr) {
422 user_data = new MayaEggGroupUserData;
423 } else {
424 // Inherit the flags from above.
425 user_data = new MayaEggGroupUserData(*parent_user_data);
426 }
427
428 if (egg_group->has_object_type("vertex-color")) {
429 egg_group->remove_object_type("vertex-color");
430 user_data->_vertex_color = true;
431 }
432 if (egg_group->has_object_type("double-sided")) {
433 egg_group->remove_object_type("double-sided");
434 user_data->_double_sided = true;
435 }
436 egg_group->set_user_data(user_data);
437 }
438
439 if (node_desc->_is_lod) {
440 // Create an LOD specification.
441 egg_group->set_lod(EggSwitchConditionDistance(node_desc->_switch_in,
442 node_desc->_switch_out,
443 LPoint3d::zero()));
444 }
445
446 node_desc->_egg_group = egg_group;
447 }
448
449 return node_desc->_egg_group;
450}
451
452/**
453 * Returns the EggTable corresponding to the joint for the indicated node.
454 * Creates the table node if it has not already been created.
455 */
457get_egg_table(MayaNodeDesc *node_desc) {
458 nassertr(_skeleton_node != nullptr, nullptr);
459 nassertr(node_desc->is_joint(), nullptr);
460
461 if (node_desc->_egg_table == nullptr) {
462 // We need to make a new table node.
463 nassertr(node_desc->_parent != nullptr, nullptr);
464
465 EggTable *egg_table = new EggTable(node_desc->get_name());
466 node_desc->_anim = new EggXfmSAnim("xform", _egg_data->get_coordinate_system());
467 node_desc->_anim->set_fps(_fps);
468 egg_table->add_child(node_desc->_anim);
469
470 if (!node_desc->_parent->is_joint()) {
471 // The parent is not a joint; put it at the top.
472 _skeleton_node->add_child(egg_table);
473
474 } else {
475 // The parent is another joint.
476 EggTable *parent_egg_table = get_egg_table(node_desc->_parent);
477 parent_egg_table->add_child(egg_table);
478 }
479
480 node_desc->_egg_table = egg_table;
481 }
482
483 return node_desc->_egg_table;
484}
485
486/**
487 * Returns the anim table corresponding to the joint for the indicated node.
488 * Creates the table node if it has not already been created.
489 */
491get_egg_anim(MayaNodeDesc *node_desc) {
492 get_egg_table(node_desc);
493 return node_desc->_anim;
494}
495
496/**
497 * Returns the anim table corresponding to the slider for the indicated blend.
498 * Creates the table node if it has not already been created.
499 */
501get_egg_slider(MayaBlendDesc *blend_desc) {
502 nassertr(_morph_node != nullptr, nullptr);
503
504 if (blend_desc->_anim == nullptr) {
505 // We need to make a new anim table.
506 EggSAnimData *egg_anim = new EggSAnimData(blend_desc->get_name());
507 egg_anim->set_fps(_fps);
508 _morph_node->add_child(egg_anim);
509
510 blend_desc->_anim = egg_anim;
511 }
512
513 return blend_desc->_anim;
514}
515
516/**
517 * Returns true if the indicated name is on the list of sliders to ignore,
518 * false otherwise.
519 */
521ignore_slider(const string &name) const {
522 return _converter->ignore_slider(name);
523}
524
525/**
526 * Outputs a message to the user reporting that a slider was ignored. Each
527 * slider is only reported once.
528 */
530report_ignored_slider(const string &name) {
531 if (_ignored_slider_names.insert(name).second) {
532 mayaegg_cat.info()
533 << "Ignoring slider " << name << "\n";
534 }
535}
536
537/**
538 * Adds the indicated MayaBlendDesc object to the list of blends collected so
539 * far. If a MayaBlendDesc object with the same name is already part of the
540 * tree, the supplied object is discarded and the previously-added object is
541 * returned; otherwise, the supplied object is added to the tree and the same
542 * object is returned.
543 *
544 * In either case, the return value is the MayaBlendDesc that should be used
545 * henceforth.
546 */
548add_blend_desc(MayaBlendDesc *blend_desc) {
549 BlendDescs::iterator bi = _blend_descs.insert(blend_desc).first;
550
551 return (*bi);
552}
553
554/**
555 * Returns the number of unique MayaBlendDesc objects (and hence the number of
556 * morph sliders) discovered in the tree.
557 */
559get_num_blend_descs() const {
560 return _blend_descs.size();
561}
562
563/**
564 * Returns the nth MayaBlendDesc object discovered in the tree.
565 */
567get_blend_desc(int n) const {
568 nassertr(n >= 0 && n < (int)_blend_descs.size(), nullptr);
569 return _blend_descs[n];
570}
571
572/**
573 * Resets all of the sliders associated with all blend shapes down to 0.
574 */
577 BlendDescs::iterator bi;
578 for (bi = _blend_descs.begin(); bi != _blend_descs.end(); ++bi) {
579 (*bi)->set_slider(0.0);
580 }
581}
582
583
584/**
585 * The recursive implementation of build_node().
586 */
587MayaNodeDesc *MayaNodeTree::
588r_build_node(const string &path) {
589 // If we have already encountered this pathname, return the corresponding
590 // MayaNodeDesc immediately.
591 NodesByPath::const_iterator ni = _nodes_by_path.find(path);
592 if (ni != _nodes_by_path.end()) {
593 return (*ni).second;
594 }
595
596 // Otherwise, we have to create it. Do this recursively, so we create each
597 // node along the path.
598 MayaNodeDesc *node_desc = nullptr;
599
600 // mayaegg_cat.info() << "path: " << path << endl;
601 if (path.empty()) {
602 // This is the top. mayaegg_cat.info() << "found empty path: " << path <<
603 // endl;
604 node_desc = _root;
605
606 } else {
607 // Maya uses vertical bars to separate path components. Remove everything
608 // from the rightmost bar on; this will give us the parent's path name.
609 size_t bar = path.rfind("|");
610 string parent_path, local_name;
611 if (bar != string::npos) {
612 parent_path = path.substr(0, bar);
613 // mayaegg_cat.info() << "parent_path: " << parent_path << endl;
614 local_name = path.substr(bar + 1);
615 if (local_name == _subroot_parent_name) {
616 node_desc = _root;
617 }
618 } else {
619 local_name = path;
620 }
621 // mayaegg_cat.info() << "local_name: " << local_name << endl;
622
623 if (node_desc != _root) {
624 MayaNodeDesc *parent_node_desc = r_build_node(parent_path);
625 if (parent_node_desc == nullptr)
626 mayaegg_cat.info() << "empty parent: " << local_name << std::endl;
627 node_desc = new MayaNodeDesc(this, parent_node_desc, local_name);
628 _nodes.push_back(node_desc);
629 }
630 }
631
632 _nodes_by_path.insert(NodesByPath::value_type(path, node_desc));
633 return node_desc;
634}
This is the primary interface into all the egg data, and the root of the egg file structure.
Definition eggData.h:37
get_coordinate_system
Returns the coordinate system in which the egg file is defined.
Definition eggData.h:73
A base class for nodes in the hierarchy that are not leaf nodes.
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
The main glue of the egg hierarchy, this corresponds to the <Group>, <Instance>, and <Joint> type nod...
Definition eggGroup.h:34
void set_tag(const std::string &key, const std::string &value)
Associates a user-defined value with a user-defined key which is stored on the node.
Definition eggGroup.I:720
bool has_object_type(const std::string &object_type) const
Returns true if the indicated object type has been added to the group, or false otherwise.
Definition eggGroup.cxx:145
bool remove_object_type(const std::string &object_type)
Removes the first instance of the indicated object type from the group if it is present.
Definition eggGroup.cxx:161
EggUserData * get_user_data() const
Returns the user data pointer most recently stored on this object, or NULL if nothing was previously ...
Definition eggObject.cxx:84
bool has_user_data() const
Returns true if a generic user data pointer has recently been set and not yet cleared,...
void set_user_data(EggUserData *user_data)
Sets the user data associated with this object.
Definition eggObject.cxx:74
void set_visibility_mode(VisibilityMode mode)
Specifies whether this geometry is to be considered normally visible, or hidden.
Corresponding to an entry, this stores a single column of numbers, for instance for a morph target,...
A SwitchCondition that switches the levels-of-detail based on distance from the camera's eyepoint.
This corresponds to a.
Definition eggTable.h:27
This corresponds to an <Xfm$Anim_S$> entry, which is a collection of up to nine entries that specify...
Definition eggXfmSAnim.h:28
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition globPattern.h:32
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
A handle to a Maya blend shape description.
This class contains extra user data which is piggybacked onto EggGroup objects for the purpose of the...
Describes a single instance of a node in the Maya scene graph, relating it to the corresponding egg s...
const MDagPath & get_dag_path() const
Returns the dag path associated with this node.
void from_dag_path(const MDagPath &dag_path, MayaToEggConverter *converter)
Indicates an association between the MayaNodeDesc and some Maya instance.
bool is_joint() const
Returns true if the node should be treated as a joint by the converter.
bool has_dag_path() const
Returns true if a Maya dag path has been associated with this node, false otherwise.
void reset_sliders()
Resets all of the sliders associated with all blend shapes down to 0.
EggGroup * get_egg_group(MayaNodeDesc *node_desc)
Returns the EggGroupNode corresponding to the group or joint for the indicated node.
void clear()
Resets the entire tree in preparation for repopulating with a new scene.
MayaNodeDesc * get_node(int n) const
Returns the nth node in the hierarchy, in an arbitrary ordering.
bool ignore_slider(const std::string &name) const
Returns true if the indicated name is on the list of sliders to ignore, false otherwise.
void tag_joint_all()
Tags the entire hierarchy for conversion.
bool tag_named(const GlobPattern &glob)
Tags nodes matching the indicated glob (and all of their children) for conversion.
MayaNodeDesc * build_node(const MDagPath &dag_path)
Returns a pointer to the node corresponding to the indicated dag_path object, creating it first if ne...
EggXfmSAnim * get_egg_anim(MayaNodeDesc *node_desc)
Returns the anim table corresponding to the joint for the indicated node.
void report_ignored_slider(const std::string &name)
Outputs a message to the user reporting that a slider was ignored.
EggTable * get_egg_table(MayaNodeDesc *node_desc)
Returns the EggTable corresponding to the joint for the indicated node.
bool tag_selected()
Tags the just the selected hierarchy for conversion, or the entire hierarchy if nothing is selected.
int get_num_nodes() const
Returns the total number of nodes in the hierarchy, not counting the root node.
void clear_egg(EggData *egg_data, EggGroupNode *egg_root, EggGroupNode *skeleton_node, EggGroupNode *morph_node)
Removes all of the references to generated egg structures from the tree, and prepares the tree for ge...
MayaBlendDesc * get_blend_desc(int n) const
Returns the nth MayaBlendDesc object discovered in the tree.
bool tag_joint_named(const GlobPattern &glob)
Tags nodes matching the indicated glob (and all of their children) for conversion.
MayaBlendDesc * add_blend_desc(MayaBlendDesc *blend_desc)
Adds the indicated MayaBlendDesc object to the list of blends collected so far.
EggSAnimData * get_egg_slider(MayaBlendDesc *blend_desc)
Returns the anim table corresponding to the slider for the indicated blend.
bool build_hierarchy()
Walks through the complete Maya hierarchy but does not tag any nodes for conversion.
bool untag_named(const GlobPattern &glob)
Un-tags nodes matching the indicated glob (and all of their children) for conversion.
int get_num_blend_descs() const
Returns the number of unique MayaBlendDesc objects (and hence the number of morph sliders) discovered...
void tag_all()
Tags the entire hierarchy for conversion.
This class supervises the construction of an EggData structure from a single Maya file,...
bool ignore_slider(const std::string &name) const
Returns true if the indicated name is on the list of sliders to ignore, false otherwise.
AnimationConvert get_animation_convert() const
Returns how source animation will be converted into egg structures.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
size_type_0 size() const
Returns the number of elements in the ordered vector.
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
This is our own Panda specialization on the default STL vector.
Definition pvector.h:42
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool get_vec3d_attribute(MObject &node, const string &attribute_name, LVecBase3d &value)
Extracts the named three-component vector from the MObject.
void get_tag_attribute_names(MObject &node, pvector< string > &tag_names)
artists should be able to set arbitrary tags.
bool get_enum_attribute(MObject &node, const string &attribute_name, string &value)
Extracts the enum attribute from the MObject as a string value.
bool has_attribute(MObject &node, const string &attribute_name)
Returns true if the node has the indicated attribute, false otherwise.
bool get_bool_attribute(MObject &node, const string &attribute_name, bool &value)
Extracts the named boolean attribute from the MObject.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.