David Rose 24 лет назад
Родитель
Сommit
c0de49ba9c

+ 56 - 0
panda/src/egg2pg/eggLoaderBase.h

@@ -0,0 +1,56 @@
+// Filename: eggLoaderBase.h
+// Created by:  drose (06Mar02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef EGGLOADERBASE_H
+#define EGGLOADERBASE_H
+
+#include "pandabase.h"
+#include "luse.h"
+
+class EggPrimitive;
+class PandaNode;
+class NamedNode;
+class ComputedVerticesMaker;
+
+///////////////////////////////////////////////////////////////////
+//       Class : EggLoaderBase
+// Description : QP: A temporary hack around having to have two kinds
+//               of EggLoaders and one kind of CharacterMaker, this
+//               presents the interface to both kinds of EggLoaders.
+////////////////////////////////////////////////////////////////////
+class EggLoaderBase {
+public:
+  virtual ~EggLoaderBase() { }
+
+  virtual void make_nonindexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
+                                         const LMatrix4d *transform = NULL) { }
+
+  virtual void make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
+                                      const LMatrix4d *transform,
+                                      ComputedVerticesMaker &_comp_verts_maker) { }
+
+  virtual void make_nonindexed_primitive(EggPrimitive *egg_prim, NamedNode *parent,
+                                         const LMatrix4d *transform = NULL) { }
+
+  virtual void make_indexed_primitive(EggPrimitive *egg_prim, NamedNode *parent,
+                                      const LMatrix4d *transform,
+                                      ComputedVerticesMaker &_comp_verts_maker) { }
+};
+
+#endif
+

+ 390 - 0
panda/src/egg2pg/qpcharacterMaker.cxx

@@ -0,0 +1,390 @@
+// Filename: qpcharacterMaker.cxx
+// Created by:  drose (06Mar02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "qpcharacterMaker.h"
+#include "qpeggLoader.h"
+#include "config_egg2pg.h"
+
+#include "computedVertices.h"
+#include "eggGroup.h"
+#include "eggPrimitive.h"
+#include "partGroup.h"
+#include "characterJoint.h"
+#include "characterJointBundle.h"
+#include "characterSlider.h"
+#include "qpcharacter.h"
+#include "transformState.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::Construtor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+qpCharacterMaker::
+qpCharacterMaker(EggGroup *root, EggLoaderBase &loader)
+  : _loader(loader), _egg_root(root) {
+
+  _character_node = new qpCharacter(_egg_root->get_name());
+  _bundle = _character_node->get_bundle();
+
+  _morph_root = (PartGroup *)NULL;
+  _skeleton_root = new PartGroup(_bundle, "<skeleton>");
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::make_node
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+qpCharacter *qpCharacterMaker::
+make_node() {
+  make_bundle();
+  _character_node->_parts = _parts;
+  return _character_node;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::egg_to_part
+//       Access: Public
+//  Description: Returns the PartGroup node associated with the given
+//               egg node.  If the egg node is not a node in the
+//               character's hierarchy, returns the top of the
+//               character's hierarchy.
+////////////////////////////////////////////////////////////////////
+PartGroup *qpCharacterMaker::
+egg_to_part(EggNode *egg_node) const {
+  int index = egg_to_index(egg_node);
+  if (index < 0) {
+    // If there's a reference to the geometry outside of the
+    // character, just return the root of the character.
+    return _bundle;
+  }
+  nassertr(index < (int)_parts.size(), NULL);
+  return _parts[index];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::egg_to_index
+//       Access: Public
+//  Description: Returns the index number associated with the
+//               PartGroup node for the given egg node, or -1.
+////////////////////////////////////////////////////////////////////
+int qpCharacterMaker::
+egg_to_index(EggNode *egg_node) const {
+  NodeMap::const_iterator nmi = _node_map.find(egg_node);
+  if (nmi == _node_map.end()) {
+    return -1;
+  }
+  return (*nmi).second;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::part_to_node
+//       Access: Public
+//  Description: Returns the scene graph node associated with the
+//               given PartGroup node, if there is one.  If the
+//               PartGroup does not have an associated node, returns
+//               the character's top node.
+////////////////////////////////////////////////////////////////////
+PandaNode *qpCharacterMaker::
+part_to_node(PartGroup *part) const {
+  if (part->is_of_type(CharacterJoint::get_class_type())) {
+    CharacterJoint *joint = DCAST(CharacterJoint, part);
+    if (joint->_qpgeom_node != (PandaNode *)NULL) {
+      return joint->_qpgeom_node;
+    }
+  }
+
+  return _character_node;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::create_slider
+//       Access: Public
+//  Description: Creates a new morph slider of the given name, and
+//               returns its index.  This is actually called by
+//               ComputedVerticesMaker, which is responsible for
+//               identifying all the unique morph target names.
+////////////////////////////////////////////////////////////////////
+int qpCharacterMaker::
+create_slider(const string &name) {
+  if (_morph_root == (PartGroup *)NULL) {
+    _morph_root = new PartGroup(_bundle, "morph");
+  }
+  CharacterSlider *slider = new CharacterSlider(_morph_root, name);
+  int index = _parts.size();
+  _parts.push_back(slider);
+  return index;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::make_bundle
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+CharacterJointBundle *qpCharacterMaker::
+make_bundle() {
+  build_joint_hierarchy(_egg_root, _skeleton_root);
+  _bundle->sort_descendants();
+
+  parent_joint_nodes(_skeleton_root);
+  make_geometry(_egg_root);
+
+  _character_node->_computed_vertices =
+    _comp_verts_maker.make_computed_vertices(_character_node, *this);
+
+  return _bundle;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::build_hierarchy
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void qpCharacterMaker::
+build_joint_hierarchy(EggNode *egg_node, PartGroup *part) {
+  int index = -1;
+
+  if (egg_node->is_of_type(EggGroup::get_class_type())) {
+    EggGroup *egg_group = DCAST(EggGroup, egg_node);
+
+    // Each joint we come across is significant, and gets added to the
+    // hierarchy.  Non-joints we encounter are ignored.
+    if (egg_group->get_group_type() == EggGroup::GT_joint) {
+      // We need to get the transform of the joint, and then convert
+      // it to single-precision.
+      LMatrix4d matd;
+      if (egg_group->has_transform()) {
+        matd = egg_group->get_transform();
+      } else {
+        matd = LMatrix4d::ident_mat();
+      }
+
+      LMatrix4f matf = LCAST(float, matd);
+
+      CharacterJoint *joint =
+        new CharacterJoint(part, egg_group->get_name(), matf);
+      index = _parts.size();
+      _parts.push_back(joint);
+
+      if (egg_group->get_dcs_flag()) {
+        // If the joint requested an explicit DCS, create a node for
+        // it.
+        joint->_qpgeom_node = new PandaNode(egg_group->get_name());
+      }
+
+      part = joint;
+    }
+
+    EggGroup::const_iterator ci;
+    for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+      build_joint_hierarchy((*ci), part);
+    }
+  }
+
+  _node_map[egg_node] = index;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::parent_joint_nodes
+//       Access: Private
+//  Description: Walks the joint hierarchy, and parents any explicit
+//               nodes created for the joints under the character
+//               node.
+////////////////////////////////////////////////////////////////////
+void qpCharacterMaker::
+parent_joint_nodes(PartGroup *part) {
+  if (part->is_of_type(CharacterJoint::get_class_type())) {
+    CharacterJoint *joint = DCAST(CharacterJoint, part);
+    PandaNode *joint_node = joint->_qpgeom_node;
+    if (joint_node != NULL) {
+      _character_node->add_child(joint_node);
+      //      joint->add_net_transform(joint_node);
+      joint_node->set_transform(TransformState::make_mat(joint->_net_transform));
+    }
+  }
+
+  for (int i = 0; i < part->get_num_children(); i++) {
+    parent_joint_nodes(part->get_child(i));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::make_geometry
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void qpCharacterMaker::
+make_geometry(EggNode *egg_node) {
+  if (egg_node->is_of_type(EggPrimitive::get_class_type())) {
+    EggPrimitive *egg_primitive = DCAST(EggPrimitive, egg_node);
+    if (!egg_primitive->empty()) {
+      EggGroupNode *prim_home = determine_primitive_home(egg_primitive);
+
+      if (prim_home == NULL) {
+        // This is a totally dynamic primitive that lives under the
+        // character's node.
+        make_dynamic_primitive(egg_primitive, _egg_root);
+
+      } else {
+        // This is a static primitive that lives under a particular
+        // node.
+        make_static_primitive(egg_primitive, prim_home);
+      }
+    }
+  }
+
+  if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
+    EggGroupNode *egg_group = DCAST(EggGroupNode, egg_node);
+
+    EggGroupNode::const_iterator ci;
+    for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+      make_geometry(*ci);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::make_static_primitive
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void qpCharacterMaker::
+make_static_primitive(EggPrimitive *egg_primitive, EggGroupNode *prim_home) {
+  PandaNode *node = part_to_node(egg_to_part(prim_home));
+
+  // We need this funny transform to convert from the coordinate
+  // space of the original vertices to that of the new joint node.
+  LMatrix4d transform =
+    egg_primitive->get_vertex_frame() *
+    prim_home->get_node_frame_inv();
+
+  _loader.make_nonindexed_primitive(egg_primitive, node, &transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::make_dynamic_primitive
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+void qpCharacterMaker::
+make_dynamic_primitive(EggPrimitive *egg_primitive, EggGroupNode *prim_home) {
+  PandaNode *node = part_to_node(egg_to_part(prim_home));
+
+  LMatrix4d transform =
+    egg_primitive->get_vertex_frame() *
+    prim_home->get_node_frame_inv();
+
+  _loader.make_indexed_primitive(egg_primitive, node, &transform,
+                                 _comp_verts_maker);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpCharacterMaker::determine_primitive_home
+//       Access: Private
+//  Description:
+////////////////////////////////////////////////////////////////////
+EggGroupNode *qpCharacterMaker::
+determine_primitive_home(EggPrimitive *egg_primitive) {
+  // A primitive's vertices may be referenced by any joint in the
+  // character.  Or, the primitive itself may be explicitly placed
+  // under a joint.
+
+  // If any of the vertices are referenced by multiple joints, or if
+  // any two vertices are referenced by different joints, then the
+  // entire primitive must be considered dynamic.  (We'll indicate a
+  // dynamic primitive by returning NULL.)
+
+  // We need to keep track of the one joint we've encountered so far,
+  // to see if all the vertices are referenced by the same joint.
+  EggGroupNode *home = NULL;
+
+  EggPrimitive::const_iterator vi;
+  for (vi = egg_primitive->begin();
+       vi != egg_primitive->end();
+       ++vi) {
+    EggVertex *vertex = (*vi);
+    if (vertex->gref_size() > 1) {
+      // This vertex is referenced by multiple joints; the primitive
+      // is dynamic.
+      return NULL;
+    }
+
+    EggGroupNode *vertex_home;
+
+    if (vertex->gref_size() == 0) {
+      // This vertex is not referenced at all, which means it belongs
+      // right where it is.
+      vertex_home = egg_primitive->get_parent();
+    } else {
+      nassertr(vertex->gref_size() == 1, NULL);
+      // This vertex is referenced exactly once.
+      vertex_home = *vertex->gref_begin();
+    }
+
+    if (home != NULL && home != vertex_home) {
+      // Oops, two vertices are referenced by different joints!  The
+      // primitive is dynamic.
+      return NULL;
+    }
+
+    home = vertex_home;
+  }
+
+  // This shouldn't be possible, unless there are no vertices--but we
+  // check for that before calling this function.
+  nassertr(home != NULL, NULL);
+
+  // So, all the vertices are assigned to the same group.  This means
+  // the polygon belongs entirely to one joint.
+
+  // If the group is not, in fact, a joint then we return the first
+  // joint above the group.
+  EggGroup *egg_group = (EggGroup *)NULL;
+  if (home->is_of_type(EggGroup::get_class_type())) {
+    egg_group = DCAST(EggGroup, home);
+  }
+  while (egg_group != (EggGroup *)NULL &&
+         egg_group->get_group_type() != EggGroup::GT_joint &&
+         egg_group->get_dart_type() == EggGroup::DT_none) {
+    nassertr(egg_group->get_parent() != (EggGroupNode *)NULL, NULL);
+    home = egg_group->get_parent();
+    egg_group = (EggGroup *)NULL;
+    if (home->is_of_type(EggGroup::get_class_type())) {
+      egg_group = DCAST(EggGroup, home);
+    }
+  }
+
+  if (egg_group != (EggGroup *)NULL &&
+      egg_group->get_group_type() == EggGroup::GT_joint &&
+      !egg_group->get_dcs_flag()) {
+    // If the home is a joint without a <DCS> flag--this is the normal
+    // case--we'll move the polygon under the character node and
+    // animate it from there explicitly.
+    return NULL;
+  }
+
+  // Otherwise, if the joint *does* have a <DCS> flag, we'll create
+  // static geometry that we parent directly to the joint node.
+  // We'll also create static geometry for polygons that have no
+  // explicit joint assignment.
+  return home;
+}

+ 6 - 6
panda/src/egg2pg/qpeggLoader.cxx

@@ -20,7 +20,7 @@
 
 #include "qpeggLoader.h"
 #include "config_egg2pg.h"
-#include "nodeChain.h"
+#include "qpnodePath.h"
 #include "renderState.h"
 #include "transformState.h"
 #include "textureAttrib.h"
@@ -154,14 +154,14 @@ reparent_decals() {
     PandaNode *node = (*di);
     nassertv(node != (PandaNode *)NULL);
 
-    // The NodeChain interface is best for this.
-    NodeChain parent(node);
+    // The qpNodePath interface is best for this.
+    qpNodePath parent(node);
 
     // First, search for the GeomNode.
-    NodeChain geom_parent;
+    qpNodePath geom_parent;
     int num_children = parent.get_num_children();
     for (int i = 0; i < num_children; i++) {
-      NodeChain child = parent.get_child(i);
+      qpNodePath child = parent.get_child(i);
 
       if (child.node()->is_of_type(qpGeomNode::get_class_type())) {
         if (!geom_parent.is_empty()) {
@@ -187,7 +187,7 @@ reparent_decals() {
       // list.
       int i = 0;
       while (i < num_children) {
-        NodeChain child = parent.get_child(i);
+        qpNodePath child = parent.get_child(i);
 
         if (child.node()->is_of_type(qpGeomNode::get_class_type())) {
           i++;