Panda3D
 All Classes Functions Variables Enumerations
characterMaker.cxx
00001 // Filename: characterMaker.cxx
00002 // Created by:  drose (06Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "characterMaker.h"
00016 #include "eggLoader.h"
00017 #include "config_egg2pg.h"
00018 #include "eggBinner.h"
00019 #include "eggGroup.h"
00020 #include "eggPrimitive.h"
00021 #include "eggBin.h"
00022 #include "partGroup.h"
00023 #include "characterJoint.h"
00024 #include "characterJointBundle.h"
00025 #include "characterSlider.h"
00026 #include "character.h"
00027 #include "geomNode.h"
00028 #include "transformState.h"
00029 #include "eggSurface.h"
00030 #include "eggCurve.h"
00031 #include "modelNode.h"
00032 #include "characterVertexSlider.h"
00033 #include "jointVertexTransform.h"
00034 #include "userVertexTransform.h"
00035 #include "eggAnimPreload.h"
00036 #include "animPreloadTable.h"
00037 
00038 
00039 
00040 
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: CharacterMaker::Construtor
00044 //       Access: Public
00045 //  Description:
00046 ////////////////////////////////////////////////////////////////////
00047 CharacterMaker::
00048 CharacterMaker(EggGroup *root, EggLoader &loader, bool structured)
00049   : _loader(loader), _egg_root(root) {
00050 
00051   _character_node = new Character(_egg_root->get_name());
00052   _bundle = _character_node->get_bundle(0);
00053 
00054   _morph_root = (PartGroup *)NULL;
00055   _skeleton_root = new PartGroup(_bundle, "<skeleton>");
00056   _structured = structured;
00057 }
00058 
00059 ////////////////////////////////////////////////////////////////////
00060 //     Function: CharacterMaker::make_node
00061 //       Access: Public
00062 //  Description:
00063 ////////////////////////////////////////////////////////////////////
00064 Character *CharacterMaker::
00065 make_node() {
00066   make_bundle();
00067   return _character_node;
00068 }
00069 
00070 ////////////////////////////////////////////////////////////////////
00071 //     Function: CharacterMaker::get_name
00072 //       Access: Public
00073 //  Description: Returns the name of the character.
00074 ////////////////////////////////////////////////////////////////////
00075 string CharacterMaker::
00076 get_name() const {
00077   return _egg_root->get_name();
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: CharacterMaker::egg_to_part
00082 //       Access: Public
00083 //  Description: Returns the PartGroup node associated with the given
00084 //               egg node.  If the egg node is not a node in the
00085 //               character's hierarchy, returns the top of the
00086 //               character's hierarchy.
00087 ////////////////////////////////////////////////////////////////////
00088 PartGroup *CharacterMaker::
00089 egg_to_part(EggNode *egg_node) const {
00090   int index = egg_to_index(egg_node);
00091   if (index < 0) {
00092     // If there's a reference to the geometry outside of the
00093     // character, just return the root of the character.
00094     return _bundle;
00095   }
00096   nassertr(index < (int)_parts.size(), NULL);
00097   return _parts[index];
00098 }
00099 
00100 ////////////////////////////////////////////////////////////////////
00101 //     Function: CharacterMaker::egg_to_transform
00102 //       Access: Public
00103 //  Description: Returns a JointVertexTransform suitable for
00104 //               applying the animation associated with the given
00105 //               egg node (which should be a joint).  Returns an
00106 //               identity transform if the egg node is not a joint in
00107 //               the character's hierarchy.
00108 ////////////////////////////////////////////////////////////////////
00109 VertexTransform *CharacterMaker::
00110 egg_to_transform(EggNode *egg_node) {
00111   int index = egg_to_index(egg_node);
00112   if (index < 0) {
00113     // Not a joint in the hierarchy.
00114     return get_identity_transform();
00115   }
00116 
00117   VertexTransforms::iterator vi = _vertex_transforms.find(index);
00118   if (vi != _vertex_transforms.end()) {
00119     return (*vi).second;
00120   }
00121 
00122   PartGroup *part = _parts[index];
00123   CharacterJoint *joint;
00124   DCAST_INTO_R(joint, part, get_identity_transform());
00125 
00126   PT(VertexTransform) vt = new JointVertexTransform(joint);
00127   _vertex_transforms[index] = vt;
00128 
00129   return vt;
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: CharacterMaker::egg_to_index
00134 //       Access: Public
00135 //  Description: Returns the index number associated with the
00136 //               PartGroup node for the given egg node, or -1.
00137 ////////////////////////////////////////////////////////////////////
00138 int CharacterMaker::
00139 egg_to_index(EggNode *egg_node) const {
00140   NodeMap::const_iterator nmi = _node_map.find(egg_node);
00141   if (nmi == _node_map.end()) {
00142     return -1;
00143   }
00144   return (*nmi).second;
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: CharacterMaker::part_to_node
00149 //       Access: Public
00150 //  Description: Returns the scene graph node associated with the
00151 //               given PartGroup node, if there is one.  If the
00152 //               PartGroup does not have an associated node, returns
00153 //               the character's top node.
00154 ////////////////////////////////////////////////////////////////////
00155 PandaNode *CharacterMaker::
00156 part_to_node(PartGroup *part, const string &name) const {
00157   PandaNode *node = _character_node;
00158 
00159   if (part->is_of_type(CharacterJoint::get_class_type())) {
00160     CharacterJoint *joint = DCAST(CharacterJoint, part);
00161     if (joint->_geom_node != (PandaNode *)NULL) {
00162       node = joint->_geom_node;
00163     }
00164   }
00165 
00166   // We should always return a GeomNode, so that all polysets
00167   // created at the same level will get added into the same
00168   // GeomNode.  Look for a child of this node.  If it doesn't have a
00169   // child yet, add a GeomNode and return it.  Otherwise, if it
00170   // already has a child, return that.
00171   if (node->is_geom_node() && node->get_name() == name) {
00172     return node;
00173   }
00174   for (int i = 0; i < node->get_num_children(); i++) {
00175     PandaNode *child = node->get_child(i);
00176     if (child->is_geom_node() && child->get_name() == name) {
00177       return child;
00178     }
00179   }
00180   PT(GeomNode) geom_node = new GeomNode(name);
00181   node->add_child(geom_node);
00182   return geom_node;
00183 }
00184 
00185 
00186 ////////////////////////////////////////////////////////////////////
00187 //     Function: CharacterMaker::create_slider
00188 //       Access: Public
00189 //  Description: Creates a new morph slider of the given name, and
00190 //               returns its index.
00191 ////////////////////////////////////////////////////////////////////
00192 int CharacterMaker::
00193 create_slider(const string &name) {
00194   if (_morph_root == (PartGroup *)NULL) {
00195     _morph_root = new PartGroup(_bundle, "morph");
00196   }
00197   CharacterSlider *slider = new CharacterSlider(_morph_root, name);
00198   int index = _parts.size();
00199   _parts.push_back(slider);
00200   return index;
00201 }
00202 
00203 ////////////////////////////////////////////////////////////////////
00204 //     Function: CharacterMaker::egg_to_slider
00205 //       Access: Public
00206 //  Description: Returns the VertexSlider corresponding to the
00207 //               indicated egg slider name.
00208 ////////////////////////////////////////////////////////////////////
00209 VertexSlider *CharacterMaker::
00210 egg_to_slider(const string &name) {
00211   VertexSliders::iterator vi = _vertex_sliders.find(name);
00212   if (vi != _vertex_sliders.end()) {
00213     return (*vi).second;
00214   }
00215 
00216   int index = create_slider(name);
00217   PT(VertexSlider) slider = 
00218     new CharacterVertexSlider(DCAST(CharacterSlider, _parts[index]));
00219   _vertex_sliders[name] = slider;
00220   return slider;
00221 }
00222 
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: CharacterMaker::make_bundle
00226 //       Access: Private
00227 //  Description:
00228 ////////////////////////////////////////////////////////////////////
00229 CharacterJointBundle *CharacterMaker::
00230 make_bundle() {
00231   build_joint_hierarchy(_egg_root, _skeleton_root, -1);
00232 
00233   //if we are structured, the egg loader is going to take care of making the geometry
00234   if(!_structured) {
00235     make_geometry(_egg_root);
00236   }
00237   _bundle->sort_descendants();
00238   parent_joint_nodes(_skeleton_root);
00239 
00240   // Now call update() one more time, to ensure that all of the joints
00241   // have their correct transform (since we might have modified the
00242   // default transform after construction).
00243   _bundle->force_update();
00244 
00245   return _bundle;
00246 }
00247 
00248 ////////////////////////////////////////////////////////////////////
00249 //     Function: CharacterMaker::build_joint_hierarchy
00250 //       Access: Private
00251 //  Description:
00252 ////////////////////////////////////////////////////////////////////
00253 void CharacterMaker::
00254 build_joint_hierarchy(EggNode *egg_node, PartGroup *part, int index) {
00255   if (egg_node->is_of_type(EggAnimPreload::get_class_type())) {
00256     EggAnimPreload *egg_anim_preload = DCAST(EggAnimPreload, egg_node);
00257 
00258     double fps = 24.0;
00259     if (egg_anim_preload->has_fps()) {
00260       fps = egg_anim_preload->get_fps();
00261     }
00262 
00263     int num_frames = 1;
00264     if (egg_anim_preload->has_num_frames()) {
00265       num_frames = egg_anim_preload->get_num_frames();
00266     }
00267 
00268     PT(AnimPreloadTable) anim_preload = _bundle->modify_anim_preload();
00269     if (anim_preload == (AnimPreloadTable *)NULL) {
00270       anim_preload = new AnimPreloadTable;
00271       _bundle->set_anim_preload(anim_preload);
00272     }
00273     anim_preload->add_anim(egg_node->get_name(), fps, num_frames);
00274     return;
00275   }
00276 
00277   if (egg_node->is_of_type(EggGroup::get_class_type())) {
00278     EggGroup *egg_group = DCAST(EggGroup, egg_node);
00279 
00280     // Each joint we come across is significant, and gets added to the
00281     // hierarchy.  Non-joints we encounter are ignored.
00282     if (egg_group->get_group_type() == EggGroup::GT_joint) {
00283       // We need to get the transform of the joint, and then convert
00284       // it to single-precision.
00285       LMatrix4d matd;
00286 
00287       // First, we get the original, initial transform from the
00288       // <Transform> entry.
00289       if (egg_group->has_transform()) {
00290         matd = egg_group->get_transform3d();
00291       } else {
00292         matd = LMatrix4d::ident_mat();
00293       }
00294 
00295       LMatrix4 matf = LCAST(PN_stdfloat, matd);
00296 
00297       CharacterJoint *joint =
00298         new CharacterJoint(_character_node, _character_node->get_bundle(0),
00299                            part, egg_group->get_name(), matf);
00300       index = _parts.size();
00301       _parts.push_back(joint);
00302 
00303       // Now that we have computed _net_transform (which we need to
00304       // convert the vertices), update the default transform from the
00305       // <DefaultPose> entry.
00306       if (egg_group->get_default_pose().has_transform()) {
00307         matd = egg_group->get_default_pose().get_transform3d();
00308         matf = LCAST(PN_stdfloat, matd);
00309         joint->_default_value = matf;
00310         joint->_value = matf;
00311       }
00312 
00313       if (egg_group->has_dcs_type()) {
00314         // If the joint requested an explicit DCS, create a node for
00315         // it.
00316         PT(ModelNode) geom_node = new ModelNode(egg_group->get_name());
00317 
00318         // To prevent flattening from messing with geometry on 
00319         // exposed joints
00320         geom_node->set_preserve_transform(ModelNode::PT_net);
00321 
00322         joint->_geom_node = geom_node.p();
00323       }
00324 
00325       part = joint;
00326     }
00327 
00328     EggGroup::const_iterator ci;
00329     for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
00330       build_joint_hierarchy((*ci), part, index);
00331     }
00332   }
00333 
00334   _node_map[egg_node] = index;
00335 }
00336 
00337 ////////////////////////////////////////////////////////////////////
00338 //     Function: CharacterMaker::parent_joint_nodes
00339 //       Access: Private
00340 //  Description: Walks the joint hierarchy, and parents any explicit
00341 //               nodes created for the joints under the character
00342 //               node.
00343 ////////////////////////////////////////////////////////////////////
00344 void CharacterMaker::
00345 parent_joint_nodes(PartGroup *part) {
00346   if (part->is_of_type(CharacterJoint::get_class_type())) {
00347     CharacterJoint *joint = DCAST(CharacterJoint, part);
00348     PandaNode *joint_node = joint->_geom_node;
00349     if (joint_node != NULL) {
00350       _character_node->add_child(joint_node);
00351       joint->add_net_transform(joint_node);
00352       joint_node->set_transform(TransformState::make_mat(joint->_net_transform));
00353     }
00354   }
00355 
00356   for (int i = 0; i < part->get_num_children(); i++) {
00357     parent_joint_nodes(part->get_child(i));
00358   }
00359 }
00360 
00361 ////////////////////////////////////////////////////////////////////
00362 //     Function: CharacterMaker::make_geometry
00363 //       Access: Private
00364 //  Description: Walks the hierarchy, looking for bins that represent
00365 //               polysets, which are to be animated with the
00366 //               character.  Invokes the egg loader to create the
00367 //               animated geometry.
00368 ////////////////////////////////////////////////////////////////////
00369 void CharacterMaker::
00370 make_geometry(EggNode *egg_node) {
00371   if (egg_node->is_of_type(EggBin::get_class_type())) {
00372     EggBin *egg_bin = DCAST(EggBin, egg_node);
00373 
00374     if (!egg_bin->empty() && 
00375         egg_bin->get_bin_number() == EggBinner::BN_polyset) {
00376       EggGroupNode *bin_home = determine_bin_home(egg_bin);
00377 
00378       bool is_dynamic;
00379       if (bin_home == (EggGroupNode *)NULL) {
00380         // This is a dynamic polyset that lives under the character's
00381         // root node.
00382         bin_home = _egg_root;
00383         is_dynamic = true;
00384       } else {
00385         // This is a totally static polyset that is parented under
00386         // some animated joint node.
00387         is_dynamic = false;
00388       }
00389 
00390       PandaNode *parent = part_to_node(egg_to_part(bin_home), egg_bin->get_name());
00391       LMatrix4d transform =
00392         egg_bin->get_vertex_frame() *
00393         bin_home->get_node_frame_inv();
00394       
00395       _loader.make_polyset(egg_bin, parent, &transform, is_dynamic,
00396                            this);
00397     }
00398   }
00399 
00400   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
00401     EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
00402 
00403     EggGroupNode::const_iterator ci;
00404     for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
00405       make_geometry(*ci);
00406     }
00407   }
00408 }
00409 
00410 ////////////////////////////////////////////////////////////////////
00411 //     Function: CharacterMaker::determine_primitive_home
00412 //       Access: Private
00413 //  Description:
00414 ////////////////////////////////////////////////////////////////////
00415 EggGroupNode *CharacterMaker::
00416 determine_primitive_home(EggPrimitive *egg_primitive) {
00417   // A primitive's vertices may be referenced by any joint in the
00418   // character.  Or, the primitive itself may be explicitly placed
00419   // under a joint.
00420 
00421   // If any of the vertices are referenced by multiple joints, or if
00422   // any two vertices are referenced by different joints, then the
00423   // entire primitive must be considered dynamic.  (We'll indicate a
00424   // dynamic primitive by returning NULL.)
00425 
00426   // We need to keep track of the one joint we've encountered so far,
00427   // to see if all the vertices are referenced by the same joint.
00428   EggGroupNode *home = NULL;
00429 
00430   EggPrimitive::const_iterator vi;
00431   for (vi = egg_primitive->begin();
00432        vi != egg_primitive->end();
00433        ++vi) {
00434     EggVertex *vertex = (*vi);
00435     if (vertex->gref_size() > 1) {
00436       // This vertex is referenced by multiple joints; the primitive
00437       // is dynamic.
00438       return NULL;
00439     }
00440 
00441     if (!vertex->_dxyzs.empty() ||
00442         !vertex->_dnormals.empty() ||
00443         !vertex->_drgbas.empty()) {
00444       // This vertex has some morph slider definitions; therefore, the
00445       // primitive is dynamic.
00446       return NULL;
00447     }
00448     EggVertex::const_uv_iterator uvi;
00449     for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
00450       if (!(*uvi)->_duvs.empty()) {
00451         // Ditto: the vertex has some UV morphs; therefore the
00452         // primitive is dynamic.
00453         return NULL;
00454       }
00455     }
00456 
00457     EggGroupNode *vertex_home;
00458 
00459     if (vertex->gref_size() == 0) {
00460       // This vertex is not referenced at all, which means it belongs
00461       // right where it is.
00462       vertex_home = egg_primitive->get_parent();
00463     } else {
00464       nassertr(vertex->gref_size() == 1, NULL);
00465       // This vertex is referenced exactly once.
00466       vertex_home = *vertex->gref_begin();
00467     }
00468 
00469     if (home != NULL && home != vertex_home) {
00470       // Oops, two vertices are referenced by different joints!  The
00471       // primitive is dynamic.
00472       return NULL;
00473     }
00474 
00475     home = vertex_home;
00476   }
00477 
00478   // This shouldn't be possible, unless there are no vertices--but we
00479   // check for that before calling this function.
00480   nassertr(home != NULL, NULL);
00481 
00482   // So, all the vertices are assigned to the same group.  This means
00483   // the polygon belongs entirely to one joint.
00484 
00485   // If the group is not, in fact, a joint then we return the first
00486   // joint above the group.
00487   EggGroup *egg_group = (EggGroup *)NULL;
00488   if (home->is_of_type(EggGroup::get_class_type())) {
00489     egg_group = DCAST(EggGroup, home);
00490   }
00491   while (egg_group != (EggGroup *)NULL &&
00492          egg_group->get_group_type() != EggGroup::GT_joint &&
00493          egg_group->get_dart_type() == EggGroup::DT_none) {
00494     nassertr(egg_group->get_parent() != (EggGroupNode *)NULL, NULL);
00495     home = egg_group->get_parent();
00496     egg_group = (EggGroup *)NULL;
00497     if (home->is_of_type(EggGroup::get_class_type())) {
00498       egg_group = DCAST(EggGroup, home);
00499     }
00500   }
00501 
00502   if (egg_group != (EggGroup *)NULL &&
00503       egg_group->get_group_type() == EggGroup::GT_joint &&
00504       !egg_group->has_dcs_type()) {
00505     // If the home is a joint without a <DCS> flag--this is the normal
00506     // case--we'll move the polygon under the character node and
00507     // animate it from there explicitly.
00508     return NULL;
00509   }
00510 
00511   // Otherwise, if the joint *does* have a <DCS> flag, we'll create
00512   // static geometry that we parent directly to the joint node.
00513   // We'll also create static geometry for polygons that have no
00514   // explicit joint assignment.
00515   return home;
00516 }
00517 
00518 ////////////////////////////////////////////////////////////////////
00519 //     Function: CharacterMaker::determine_bin_home
00520 //       Access: Private
00521 //  Description: Examines the joint assignment of the vertices of all
00522 //               of the primitives within this bin to determine which
00523 //               parent node the bin's polyset should be created
00524 //               under.
00525 ////////////////////////////////////////////////////////////////////
00526 EggGroupNode *CharacterMaker::
00527 determine_bin_home(EggBin *egg_bin) {
00528   // A primitive's vertices may be referenced by any joint in the
00529   // character.  Or, the primitive itself may be explicitly placed
00530   // under a joint.
00531 
00532   // If any of the vertices, in any primitive, are referenced by
00533   // multiple joints, or if any two vertices are referenced by
00534   // different joints, then the entire bin must be considered dynamic.
00535   // (We'll indicate a dynamic bin by returning NULL.)
00536 
00537   if (!egg_rigid_geometry) {
00538     // If we don't have egg-rigid-geometry enabled, then all geometry
00539     // is considered dynamic.
00540     return NULL;
00541   }
00542 
00543   // We need to keep track of the one joint we've encountered so far,
00544   // to see if all the vertices are referenced by the same joint.
00545   EggGroupNode *home = NULL;
00546 
00547   EggGroupNode::const_iterator ci;
00548   for (ci = egg_bin->begin(); ci != egg_bin->end(); ++ci) {
00549     CPT(EggPrimitive) egg_primitive = DCAST(EggPrimitive, (*ci));
00550 
00551     EggPrimitive::const_iterator vi;
00552     for (vi = egg_primitive->begin();
00553          vi != egg_primitive->end();
00554          ++vi) {
00555       EggVertex *vertex = (*vi);
00556       if (vertex->gref_size() > 1) {
00557         // This vertex is referenced by multiple joints; the primitive
00558         // is dynamic.
00559         return NULL;
00560       }
00561       
00562       if (!vertex->_dxyzs.empty() ||
00563           !vertex->_dnormals.empty() ||
00564           !vertex->_drgbas.empty()) {
00565         // This vertex has some morph slider definitions; therefore, the
00566         // primitive is dynamic.
00567         return NULL;
00568       }
00569       EggVertex::const_uv_iterator uvi;
00570       for (uvi = vertex->uv_begin(); uvi != vertex->uv_end(); ++uvi) {
00571         if (!(*uvi)->_duvs.empty()) {
00572           // Ditto: the vertex has some UV morphs; therefore the
00573           // primitive is dynamic.
00574           return NULL;
00575         }
00576       }
00577 
00578       EggGroupNode *vertex_home;
00579       
00580       if (vertex->gref_size() == 0) {
00581         // This vertex is not referenced at all, which means it belongs
00582         // right where it is.
00583         vertex_home = egg_primitive->get_parent();
00584       } else {
00585         nassertr(vertex->gref_size() == 1, NULL);
00586         // This vertex is referenced exactly once.
00587         vertex_home = *vertex->gref_begin();
00588       }
00589       
00590       if (home != NULL && home != vertex_home) {
00591         // Oops, two vertices are referenced by different joints!  The
00592         // primitive is dynamic.
00593         return NULL;
00594       }
00595 
00596       home = vertex_home;
00597     }
00598   }
00599 
00600   // This shouldn't be possible, unless there are no vertices--but we
00601   // eliminate invalid primitives before we begin, so all primitives
00602   // should have vertices, and all bins should have primitives.
00603   nassertr(home != NULL, NULL);
00604 
00605   // So, all the vertices are assigned to the same group.  This means
00606   // all the primitives in the bin belong entirely to one joint.
00607 
00608   // If the group is not, in fact, a joint then we return the first
00609   // joint above the group.
00610   EggGroup *egg_group = (EggGroup *)NULL;
00611   if (home->is_of_type(EggGroup::get_class_type())) {
00612     egg_group = DCAST(EggGroup, home);
00613   }
00614   while (egg_group != (EggGroup *)NULL &&
00615          egg_group->get_group_type() != EggGroup::GT_joint &&
00616          egg_group->get_dart_type() == EggGroup::DT_none) {
00617     nassertr(egg_group->get_parent() != (EggGroupNode *)NULL, NULL);
00618     home = egg_group->get_parent();
00619     egg_group = (EggGroup *)NULL;
00620     if (home->is_of_type(EggGroup::get_class_type())) {
00621       egg_group = DCAST(EggGroup, home);
00622     }
00623   }
00624 
00625   if (egg_group != (EggGroup *)NULL &&
00626       egg_group->get_group_type() == EggGroup::GT_joint &&
00627       !egg_group->has_dcs_type()) {
00628     // If we have rigid geometry that is assigned to a joint without a
00629     // <DCS> flag, which means the joint didn't get created as its own
00630     // node, go ahead and make an implicit node for the joint.
00631 
00632     if (egg_group->get_dcs_type() == EggGroup::DC_none) {
00633       // Unless the user specifically forbade exposing the joint by
00634       // putting an explicit "<DCS> { none }" entry in the joint.  In
00635       // this case, we return NULL to treat the geometry as dynamic
00636       // (and animate it by animating its vertices), but display lists
00637       // and vertex buffers will perform better if more geometry is
00638       // rigid.  There's a tradeoff, though, since the cull traverser
00639       // will have to do more work with additional transforms in the
00640       // scene graph, and this may also break up the geometry into
00641       // more individual pieces, which is the biggest limiting factor
00642       // on modern PC graphics cards.
00643       return NULL;
00644     }
00645 
00646     CharacterJoint *joint;
00647     DCAST_INTO_R(joint, egg_to_part(egg_group), home);
00648     egg_group->set_dcs_type(EggGroup::DC_default);
00649 
00650     PT(ModelNode) geom_node = new ModelNode(egg_group->get_name());
00651     geom_node->set_preserve_transform(ModelNode::PT_local);
00652     joint->_geom_node = geom_node.p();
00653   }
00654 
00655   return home;
00656 }
00657 
00658 ////////////////////////////////////////////////////////////////////
00659 //     Function: CharacterMaker::get_identity_transform
00660 //       Access: Private
00661 //  Description: Returns a VertexTransform that represents the root of
00662 //               the character--it never animates.
00663 ////////////////////////////////////////////////////////////////////
00664 VertexTransform *CharacterMaker::
00665 get_identity_transform() {
00666   if (_identity_transform == (VertexTransform *)NULL) {
00667     _identity_transform = new UserVertexTransform("root");
00668   }
00669   return _identity_transform;
00670 }
 All Classes Functions Variables Enumerations