Panda3D
 All Classes Functions Variables Enumerations
maxNodeTree.cxx
1 // Filename: maxNodeTree.cxx
2 // Created by: crevilla
3 // from mayaNodeTree.cxx created by: drose (06Jun03)
4 //
5 ////////////////////////////////////////////////////////////////////
6 //
7 // PANDA 3D SOFTWARE
8 // Copyright (c) Carnegie Mellon University. All rights reserved.
9 //
10 // All use of this software is subject to the terms of the revised BSD
11 // license. You should have received a copy of this license along
12 // with this source code in a file named "LICENSE."
13 //
14 ////////////////////////////////////////////////////////////////////
15 
16 #include "maxEgg.h"
17 
18 ////////////////////////////////////////////////////////////////////
19 // Function: MaxNodeTree::Constructor
20 // Access: Public
21 // Description:
22 ////////////////////////////////////////////////////////////////////
23 MaxNodeTree::
24 MaxNodeTree() {
25  _root = new MaxNodeDesc;
26  _fps = 0.0;
27  _export_mesh = false;
28  _egg_data = (EggData *)NULL;
29  _egg_root = (EggGroupNode *)NULL;
30  _skeleton_node = (EggGroupNode *)NULL;
31 }
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: MaxNodeTree::build_node
35 // Access: Public
36 // Description: Returns a pointer to the node corresponding to the
37 // indicated INode object, creating it first if
38 // necessary.
39 ////////////////////////////////////////////////////////////////////
41 build_node(INode *max_node) {
42  MaxNodeDesc *node_desc = r_build_node(max_node);
43  node_desc->from_INode(max_node);
44 
45  if (node_desc->is_node_joint()) {
46  node_desc->_joint_entry = build_joint(max_node, node_desc);
47  }
48  return node_desc;
49 }
50 
51 ////////////////////////////////////////////////////////////////////
52 // Function: MaxNodeTree::build_joint
53 // Access: Public
54 // Description: Returns a pointer to the node corresponding to the
55 // indicated INode object, creating it first if
56 // necessary.
57 ////////////////////////////////////////////////////////////////////
59 build_joint(INode *max_node, MaxNodeDesc *node_joint) {
60  MaxNodeDesc *node_desc = r_build_joint(node_joint, max_node);
61  node_desc->from_INode(max_node);
62  node_desc->set_joint(true);
63  return node_desc;
64 }
65 
66 bool MaxNodeTree::node_in_list(ULONG handle, ULONG *list, int len) {
67  if (!list) return true;
68  for (int i = 0; i < len; i++)
69  if (list[i] == handle) return true;
70  return false;
71 }
72 
73 bool MaxNodeTree::is_joint(INode *node) {
74  Control *c = node->GetTMController();
75  return (node->GetBoneNodeOnOff() || //joints
76  (c && //bipeds
77  ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) ||
78  (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) ||
79  (c->ClassID() == FOOTPRINT_CLASS_ID))));
80 }
81 
82 bool MaxNodeTree::
83 r_build_hierarchy(INode *root, ULONG *selection_list, int len) {
84  if (node_in_list(root->GetHandle(), selection_list, len))
85  build_node(root);
86  // Export children
87  for ( int i = 0; i < root->NumberOfChildren(); i++ ) {
88  // *** Should probably be checking the return value of the following line
89  r_build_hierarchy(root->GetChildNode(i), selection_list, len);
90  }
91  return true;
92 }
93 ////////////////////////////////////////////////////////////////////
94 // Function: MaxNodeTree::build_complete_hierarchy
95 // Access: Public
96 // Description: Walks through the complete Max hierarchy and builds
97 // up the corresponding tree.
98 ////////////////////////////////////////////////////////////////////
99 bool MaxNodeTree::
100 build_complete_hierarchy(INode *root, ULONG *selection_list, int len) {
101 
102  // Get the entire Max scene.
103  if (root == NULL) {
104  // *** Log an error
105  return false;
106  }
107 
108  bool all_ok = true;
109  r_build_hierarchy(root, selection_list, len);
110 
111  if (all_ok) {
112  _root->check_pseudo_joints(false);
113  }
114 
115  return all_ok;
116 }
117 
118 ////////////////////////////////////////////////////////////////////
119 // Function: MaxNodeTree::get_num_nodes
120 // Access: Public
121 // Description: Returns the total number of nodes in the hierarchy,
122 // not counting the root node.
123 ////////////////////////////////////////////////////////////////////
124 int MaxNodeTree::
125 get_num_nodes() const {
126  return _nodes.size();
127 }
128 
129 ////////////////////////////////////////////////////////////////////
130 // Function: MaxNodeTree::get_node
131 // Access: Public
132 // Description: Returns the nth node in the hierarchy, in an
133 // arbitrary ordering.
134 ////////////////////////////////////////////////////////////////////
136 get_node(int n) const {
137  nassertr(n >= 0 && n < (int)_nodes.size(), NULL);
138  return _nodes[n];
139 }
140 
141 ////////////////////////////////////////////////////////////////////
142 // Function: MaxNodeTree::clear_egg
143 // Access: Public
144 // Description: Removes all of the references to generated egg
145 // structures from the tree, and prepares the tree for
146 // generating new egg structures.
147 ////////////////////////////////////////////////////////////////////
148 void MaxNodeTree::
149 clear_egg(EggData *egg_data, EggGroupNode *egg_root,
150  EggGroupNode *skeleton_node) {
151  _root->clear_egg();
152  _egg_data = egg_data;
153  _egg_root = egg_root;
154  _skeleton_node = skeleton_node;
155 }
156 
157 ////////////////////////////////////////////////////////////////////
158 // Function: MaxNodeTree::get_egg_group
159 // Access: Public
160 // Description: Returns the EggGroupNode corresponding to the group
161 // or joint for the indicated node. Creates the group
162 // node if it has not already been created.
163 ////////////////////////////////////////////////////////////////////
166  nassertr(_egg_root != (EggGroupNode *)NULL, NULL);
167 
168  if (node_desc->_egg_group == (EggGroup *)NULL) {
169  // We need to make a new group node.
170  EggGroup *egg_group;
171 
172  nassertr(node_desc->_parent != (MaxNodeDesc *)NULL, NULL);
173  egg_group = new EggGroup(node_desc->get_name());
174  if (node_desc->is_joint()) {
175  egg_group->set_group_type(EggGroup::GT_joint);
176  }
177  if (node_desc->_parent == _root) {
178  // The parent is the root.
179  // Set collision properties for the root if it has them:
180  if(!_export_mesh)
181  {
182  set_collision_tags(node_desc, egg_group);
183  }
184  _egg_root->add_child(egg_group);
185 
186  } else {
187  // The parent is another node.
188  // if export mesh, the tag should be added at the second level
189  if(_export_mesh)
190  {
191  if(node_desc->_parent->_parent == _root)
192  {
193  set_collision_tags(node_desc, egg_group);
194  }
195  }
196  EggGroup *parent_egg_group = get_egg_group(node_desc->_parent);
197  parent_egg_group->add_child(egg_group);
198  }
199 
200  node_desc->_egg_group = egg_group;
201  }
202 
203  return node_desc->_egg_group;
204 }
205 
206 ////////////////////////////////////////////////////////////////////
207 // Function: MaxNodeTree::get_egg_table
208 // Access: Public
209 // Description: Returns the EggTable corresponding to the joint
210 // for the indicated node. Creates the table node if it
211 // has not already been created.
212 ////////////////////////////////////////////////////////////////////
215  nassertr(_skeleton_node != (EggGroupNode *)NULL, NULL);
216  nassertr(node_desc->is_joint(), NULL);
217 
218  if (node_desc->_egg_table == (EggTable *)NULL) {
219  // We need to make a new table node.
220  nassertr(node_desc->_parent != (MaxNodeDesc *)NULL, NULL);
221 
222  EggTable *egg_table = new EggTable(node_desc->get_name());
223  node_desc->_anim = new EggXfmSAnim("xform",
224  _egg_data->get_coordinate_system());
225  node_desc->_anim->set_fps(_fps);
226  egg_table->add_child(node_desc->_anim);
227 
228  if (!node_desc->_parent->is_joint()) {
229  // The parent is not a joint; put it at the top.
230  _skeleton_node->add_child(egg_table);
231 
232  } else {
233  // The parent is another joint.
234  EggTable *parent_egg_table = get_egg_table(node_desc->_parent);
235  parent_egg_table->add_child(egg_table);
236  }
237 
238  node_desc->_egg_table = egg_table;
239  }
240 
241  return node_desc->_egg_table;
242 }
243 
244 ////////////////////////////////////////////////////////////////////
245 // Function: MaxNodeTree::get_egg_anim
246 // Access: Public
247 // Description: Returns the anim table corresponding to the joint
248 // for the indicated node. Creates the table node if it
249 // has not already been created.
250 ////////////////////////////////////////////////////////////////////
253  get_egg_table(node_desc);
254  return node_desc->_anim;
255 }
256 
257 ////////////////////////////////////////////////////////////////////
258 // Function: MaxNodeTree::r_build_node
259 // Access: Private
260 // Description: The recursive implementation of build_node().
261 ////////////////////////////////////////////////////////////////////
262 MaxNodeDesc *MaxNodeTree::
263 r_build_node(INode* max_node) {
264  // If we have already encountered this pathname, return the
265  // corresponding MaxNodeDesc immediately.
266 
267  ULONG node_handle = 0;
268 
269  if (max_node) {
270  node_handle = max_node->GetHandle();
271  }
272 
273  NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle);
274  if (ni != _nodes_by_path.end()) {
275  return (*ni).second;
276  }
277 
278  // Otherwise, we have to create it. Do this recursively, so we
279  // create each node along the path.
280  MaxNodeDesc *node_desc;
281 
282  if (!max_node) {
283  // This is the top.
284  node_desc = _root;
285 
286  } else {
287  INode *parent_node;
288 
289  if (max_node->IsRootNode()) {
290  parent_node = NULL;
291  } else {
292  parent_node = max_node->GetParentNode();
293  }
294 
295  MaxNodeDesc *parent_node_desc = r_build_node(parent_node);
296  node_desc = new MaxNodeDesc(parent_node_desc, max_node);
297  _nodes.push_back(node_desc);
298  }
299 
300  _nodes_by_path.insert(NodesByPath::value_type(node_handle, node_desc));
301  return node_desc;
302 }
303 
304 ////////////////////////////////////////////////////////////////////
305 // Function: MaxNodeTree::r_build_joint
306 // Access: Private
307 // Description: The recursive implementation of build_joint().
308 ////////////////////////////////////////////////////////////////////
309 MaxNodeDesc *MaxNodeTree::
310 r_build_joint(MaxNodeDesc *node_desc, INode *max_node)
311 {
312  MaxNodeDesc *node_joint;
313  if (node_desc == _root) {
314  node_joint = new MaxNodeDesc(_root, max_node);
315  _nodes.push_back(node_joint);
316  return node_joint;
317  } else if (node_desc->is_node_joint() && node_desc->_joint_entry) {
318  node_joint = new MaxNodeDesc(node_desc->_joint_entry, max_node);
319  _nodes.push_back(node_joint);
320  return node_joint;
321  } else {
322  return r_build_joint(node_desc->_parent, max_node);
323  }
324 }
325 
326 ////////////////////////////////////////////////////////////////////
327 // Function: MaxNodeTree::find_node
328 // Access: Private
329 // Description: The recursive implementation of build_node().
330 ////////////////////////////////////////////////////////////////////
332 find_node(INode* max_node) {
333  // If we have already encountered this pathname, return the
334  // corresponding MaxNodeDesc immediately.
335 
336  ULONG node_handle = 0;
337 
338  if (max_node) {
339  node_handle = max_node->GetHandle();
340  }
341 
342  NodesByPath::const_iterator ni = _nodes_by_path.find(node_handle);
343  if (ni != _nodes_by_path.end()) {
344  return (*ni).second;
345  }
346 
347  return NULL;
348 }
349 
350 ////////////////////////////////////////////////////////////////////
351 // Function: MaxNodeTree::find_joint
352 // Access: Private
353 // Description: The recursive implementation of build_node().
354 ////////////////////////////////////////////////////////////////////
356 find_joint(INode* max_node)
357 {
358  MaxNodeDesc *node = find_node(max_node);
359  if (!node || (is_joint(max_node) && !node->is_node_joint()))
360  node = build_node(max_node);
361  return node->_joint_entry;
362 }
363 
364 ////////////////////////////////////////////////////////////////////
365 // Function: MaxNodeTree::set_collision_tags
366 // Access: Private
367 // Description: Sets the corresponding collision tag to the egg_group
368 // based on the User Defined Tab in the object properties
369 // panel
370 ////////////////////////////////////////////////////////////////////
371 void MaxNodeTree::set_collision_tags(MaxNodeDesc *node_desc, EggGroup *egg_group) {
372  //Max has huge problems passing strings and bools to Get and SetUserProp
373  //So instead we have to use Integers. Now we have to check
374  //for every collide type, then get its collide flags and
375  //do some number crunching to get the actual flag into the group
376 
377  int check = 1; //is the value true. This could be anything really
378 
379  //We have to check each collision type in turn to see if it's true
380  //Ugly but it works per object, not globaly
381  if (node_desc->get_max_node()->GetUserPropInt(_T("polyset"), check)) {
382  //we have a polyset.
383  if (check == 1) {
384  egg_group->set_collision_name(node_desc->get_name());
385  egg_group->set_cs_type(EggGroup::CST_polyset);
386  }
387  }
388  if (node_desc->get_max_node()->GetUserPropInt(_T("plane"), check)) {
389  //plane
390  if (check == 1) {
391  egg_group->set_collision_name(node_desc->get_name());
392  egg_group->set_cs_type(EggGroup::CST_plane);
393  }
394  }
395  if (node_desc->get_max_node()->GetUserPropInt(_T("polygon"), check)) {
396  //polygon
397  if (check == 1) {
398  egg_group->set_collision_name(node_desc->get_name());
399  egg_group->set_cs_type(EggGroup::CST_polygon);
400  }
401  }
402  if (node_desc->get_max_node()->GetUserPropInt(_T("sphere"), check)) {
403  //sphere
404  if (check == 1) {
405  egg_group->set_collision_name(node_desc->get_name());
406  egg_group->set_cs_type(EggGroup::CST_sphere);
407  }
408  }
409  if (node_desc->get_max_node()->GetUserPropInt(_T("inv-sphere"), check)) {
410  //invsphere
411  if (check == 1) {
412  egg_group->set_collision_name(node_desc->get_name());
413  egg_group->set_cs_type(EggGroup::CST_inv_sphere);
414  }
415  }
416  if (node_desc->get_max_node()->GetUserPropInt(_T("invsphere"), check)) {
417  //invsphere (different spelling)
418  if (check == 1) {
419  egg_group->set_collision_name(node_desc->get_name());
420  egg_group->set_cs_type(EggGroup::CST_inv_sphere);
421  }
422  }
423  if (node_desc->get_max_node()->GetUserPropInt(_T("tube"), check)) {
424  //tube
425  if (check == 1) {
426  egg_group->set_collision_name(node_desc->get_name());
427  egg_group->set_cs_type(EggGroup::CST_tube);
428  }
429  }
430  if (node_desc->get_max_node()->GetUserPropInt(_T("floor-mesh"), check)) {
431  //floor-mesh
432  if (check == 1) {
433  egg_group->set_collision_name(node_desc->get_name());
434  egg_group->set_cs_type(EggGroup::CST_floor_mesh);
435  }
436  }
437 
438  if (node_desc->get_max_node()->GetUserPropInt(_T("descend"), check)) {
439  if (check == 1) {
440  //we have the descend flag specified
441  egg_group->set_collide_flags(EggGroup::CF_descend);
442  }
443  }
444  if (node_desc->get_max_node()->GetUserPropInt(_T("event"), check)) {
445  if (check == 1) {
446  //we have the event flag specified
447  egg_group->set_collide_flags(EggGroup::CF_event);
448  }
449  }
450  if (node_desc->get_max_node()->GetUserPropInt(_T("keep"), check)) {
451  if (check == 1) {
452  //we have the keep flag specified
453  egg_group->set_collide_flags(EggGroup::CF_keep);
454  }
455  }
456  if (node_desc->get_max_node()->GetUserPropInt(_T("solid"), check)) {
457  if (check == 1) {
458  //we have the solid flag specified
459  egg_group->set_collide_flags(EggGroup::CF_solid);
460  }
461  }
462  if (node_desc->get_max_node()->GetUserPropInt(_T("center"), check)) {
463  if (check == 1) {
464  //we have the center flag specified
465  egg_group->set_collide_flags(EggGroup::CF_center);
466  }
467  }
468  if (node_desc->get_max_node()->GetUserPropInt(_T("turnstile"), check)) {
469  if (check == 1) {
470  //we have the turnstile flag specified
471  egg_group->set_collide_flags(EggGroup::CF_turnstile);
472  }
473  }
474  if (node_desc->get_max_node()->GetUserPropInt(_T("level"), check)) {
475  if (check == 1) {
476  //we have the level flag specified
477  egg_group->set_collide_flags(EggGroup::CF_level);
478  }
479  }
480  if (node_desc->get_max_node()->GetUserPropInt(_T("intangible"), check)) {
481  if (check == 1) {
482  //we have the intangible flag specified
483  egg_group->set_collide_flags(EggGroup::CF_intangible);
484  }
485  }
486  return;
487 }
EggGroup * get_egg_group(MaxNodeDesc *node_desc)
Returns the EggGroupNode corresponding to the group or joint for the indicated node.
bool is_joint() const
Returns true if the node should be treated as a joint by the converter.
A base class for nodes in the hierarchy that are not leaf nodes.
Definition: eggGroupNode.h:51
EggXfmSAnim * get_egg_anim(MaxNodeDesc *node_desc)
Returns the anim table corresponding to the joint for the indicated node.
MaxNodeDesc * build_node(INode *max_node)
Returns a pointer to the node corresponding to the indicated INode object, creating it first if neces...
Definition: maxNodeTree.cxx:41
bool is_node_joint() const
Returns true if the node is the parent or ancestor of a joint.
MaxNodeDesc * get_node(int n) const
Returns the nth node in the hierarchy, in an arbitrary ordering.
bool build_complete_hierarchy(INode *root, ULONG *selection_list, int len)
Walks through the complete Max hierarchy and builds up the corresponding tree.
MaxNodeDesc * find_joint(INode *max_node)
The recursive implementation of build_node().
INode * get_max_node() const
Returns the INode associated with this node.
This is the primary interface into all the egg data, and the root of the egg file structure...
Definition: eggData.h:41
void from_INode(INode *max_node)
Indicates an associated between the MaxNodeDesc and some Max Node instance.
Definition: maxNodeDesc.cxx:71
MaxNodeDesc * build_joint(INode *max_node, MaxNodeDesc *node_joint)
Returns a pointer to the node corresponding to the indicated INode object, creating it first if neces...
Definition: maxNodeTree.cxx:59
The main glue of the egg hierarchy, this corresponds to the &lt;Group&gt;, &lt;Instance&gt;, and &lt;Joint&gt; type nod...
Definition: eggGroup.h:36
CoordinateSystem get_coordinate_system() const
Returns the coordinate system in which the egg file is defined.
Definition: eggData.I:111
void clear_egg(EggData *egg_data, EggGroupNode *egg_root, EggGroupNode *skeleton_node)
Removes all of the references to generated egg structures from the tree, and prepares the tree for ge...
This corresponds to an &lt;Xfm$Anim_S$&gt; entry, which is a collection of up to nine &lt;S$Anim&gt; entries that...
Definition: eggXfmSAnim.h:33
Describes a single instance of a node in the Max scene graph, relating it to the corresponding egg st...
Definition: maxNodeDesc.h:26
int get_num_nodes() const
Returns the total number of nodes in the hierarchy, not counting the root node.
MaxNodeDesc * find_node(INode *max_node)
The recursive implementation of build_node().
This corresponds to a.
Definition: eggTable.h:31
EggNode * add_child(EggNode *node)
Adds the indicated child to the group and returns it.
EggTable * get_egg_table(MaxNodeDesc *node_desc)
Returns the EggTable corresponding to the joint for the indicated node.