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