Browse Source

obviate the need to call Actor.update() most of the time

David Rose 19 years ago
parent
commit
8e178ae9d6

+ 7 - 2
panda/src/char/Sources.pp

@@ -12,7 +12,9 @@
   #define SOURCES \
     character.I character.h \
     characterJoint.h characterJointBundle.I  \
-    characterJointBundle.h characterSlider.h \
+    characterJointBundle.h \
+    characterJointEffect.h characterJointEffect.I \
+    characterSlider.h \
     characterVertexSlider.I characterVertexSlider.h \
     config_char.h \
     jointVertexTransform.I jointVertexTransform.h
@@ -20,6 +22,7 @@
   #define INCLUDED_SOURCES \
     character.cxx \
     characterJoint.cxx characterJointBundle.cxx  \
+    characterJointEffect.cxx \
     characterSlider.cxx \
     characterVertexSlider.cxx \
     config_char.cxx  \
@@ -28,7 +31,9 @@
   #define INSTALL_HEADERS \
     character.I character.h \
     characterJoint.h characterJointBundle.I \
-    characterJointBundle.h characterSlider.h \
+    characterJointBundle.h \
+    characterJointEffect.h characterJointEffect.I \
+    characterSlider.h \
     characterVertexSlider.I characterVertexSlider.h \
     config_char.h \
     jointVertexTransform.I jointVertexTransform.h

+ 0 - 1
panda/src/char/char_composite1.cxx

@@ -1,4 +1,3 @@
-
 #include "config_char.cxx"
 #include "character.cxx"
 #include "characterJoint.cxx"

+ 1 - 1
panda/src/char/char_composite2.cxx

@@ -1,4 +1,4 @@
-
+#include "characterJointEffect.cxx"
 #include "characterSlider.cxx"
 #include "characterVertexSlider.cxx"
 #include "jointVertexTransform.cxx"

+ 29 - 0
panda/src/char/character.cxx

@@ -74,6 +74,7 @@ Character(const string &name) :
 ////////////////////////////////////////////////////////////////////
 Character::
 ~Character() {
+  r_clear_joint_characters(get_bundle());
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -251,6 +252,9 @@ copy_joints(PartGroup *copy, PartGroup *orig) {
   for (ci = orig->_children.begin(); ci != orig->_children.end(); ++ci) {
     PartGroup *orig_child = (*ci);
     PartGroup *copy_child = orig_child->make_copy();
+    if (copy_child->is_of_type(CharacterJoint::get_class_type())) {
+      DCAST(CharacterJoint, copy_child)->set_character(this);
+    }
     copy->_children.push_back(copy_child);
     copy_joints(copy_child, orig_child);
   }
@@ -449,6 +453,7 @@ copy_node_pointers(const Character *from, const Character::NodeMap &node_map) {
           // Here's an internal joint that the source Character was
           // animating directly.  We'll animate our corresponding
           // joint the same way.
+          dest_joint->set_character(this);
           dest_joint->add_net_transform(dest_node);
         }
       }
@@ -466,6 +471,7 @@ copy_node_pointers(const Character *from, const Character::NodeMap &node_map) {
           // Here's an internal joint that the source Character was
           // animating directly.  We'll animate our corresponding
           // joint the same way.
+          dest_joint->set_character(this);
           dest_joint->add_local_transform(dest_node);
         }
       }
@@ -633,6 +639,29 @@ redirect_slider(const VertexSlider *vs, Character::GeomSliderMap &gsmap) {
   return new_cvs;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Character::r_clear_joint_characters
+//       Access: Private
+//  Description: Recursively walks through the joint hierarchy and
+//               clears any _character pointers on all the joints.
+//               Intended to be called just before Character
+//               destruction.
+////////////////////////////////////////////////////////////////////
+void Character::
+r_clear_joint_characters(PartGroup *part) {
+  if (part->is_of_type(CharacterJoint::get_class_type())) {
+    CharacterJoint *joint = DCAST(CharacterJoint, part);
+    nassertv(joint->get_character() == this);
+    joint->set_character(NULL);
+  }
+
+  int num_children = part->get_num_children();
+  for (int i = 0; i < num_children; ++i) {
+    PartGroup *child = part->get_child(i);
+    r_clear_joint_characters(child);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Character::register_with_read_factory
 //       Access: Public, Static

+ 2 - 0
panda/src/char/character.h

@@ -107,6 +107,8 @@ private:
                                           GeomJointMap &gjmap);
   PT(CharacterVertexSlider) redirect_slider(const VertexSlider *vs, GeomSliderMap &gsmap);
 
+  void r_clear_joint_characters(PartGroup *part);
+
   // This vector is used by the ComputedVertices object to index back
   // into our joints and sliders.
   typedef vector_PartGroupStar Parts;

+ 162 - 20
panda/src/char/characterJoint.cxx

@@ -19,7 +19,7 @@
 #include "characterJoint.h"
 #include "config_char.h"
 #include "jointVertexTransform.h"
-
+#include "characterJointEffect.h"
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "bamReader.h"
@@ -33,7 +33,9 @@ TypeHandle CharacterJoint::_type_handle;
 //  Description: For internal use only.
 ////////////////////////////////////////////////////////////////////
 CharacterJoint::
-CharacterJoint() {
+CharacterJoint() :
+  _character(NULL)
+{
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -44,6 +46,7 @@ CharacterJoint() {
 CharacterJoint::
 CharacterJoint(const CharacterJoint &copy) :
   MovingPartMatrix(copy),
+  _character(NULL),
   _net_transform(copy._net_transform),
   _initial_net_transform_inverse(copy._initial_net_transform_inverse)
 {
@@ -56,9 +59,11 @@ CharacterJoint(const CharacterJoint &copy) :
 //  Description:
 ////////////////////////////////////////////////////////////////////
 CharacterJoint::
-CharacterJoint(PartGroup *parent, const string &name,
-               const LMatrix4f &initial_value)
-  : MovingPartMatrix(parent, name, initial_value)
+CharacterJoint(Character *character,
+               PartGroup *parent, const string &name,
+               const LMatrix4f &initial_value) :
+  MovingPartMatrix(parent, name, initial_value),
+  _character(character)
 {
   Thread *current_thread = Thread::get_current_thread();
 
@@ -79,6 +84,7 @@ CharacterJoint(PartGroup *parent, const string &name,
 CharacterJoint::
 ~CharacterJoint() {
   nassertv(_vertex_transforms.empty());
+  nassertv(_character == (Character *)NULL);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -179,9 +185,15 @@ update_internals(PartGroup *parent, bool self_changed, bool parent_changed,
 //               from the root.  Returns true if the node is
 //               successfully added, false if it had already been
 //               added.
+//
+//               A CharacterJointEffect for this joint's Character
+//               will automatically be added to the specified node.
 ////////////////////////////////////////////////////////////////////
 bool CharacterJoint::
 add_net_transform(PandaNode *node) {
+  if (_character != (Character *)NULL) {
+    node->set_effect(CharacterJointEffect::make(_character));
+  }
   return _net_transform_nodes.insert(node).second;
 }
 
@@ -193,9 +205,18 @@ add_net_transform(PandaNode *node) {
 //               transform from the root.  Returns true if the node is
 //               successfully removed, false if it was not on the
 //               list.
+//
+//               If the node has a CharacterJointEffect that matches
+//               this joint's Character, it will be cleared.
 ////////////////////////////////////////////////////////////////////
 bool CharacterJoint::
 remove_net_transform(PandaNode *node) {
+  CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
+  if (effect != (RenderEffect *)NULL &&
+      DCAST(CharacterJointEffect, effect)->get_character() == _character) {
+    node->clear_effect(CharacterJointEffect::get_class_type());
+  }
+
   return (_net_transform_nodes.erase(node) > 0);
 }
 
@@ -220,6 +241,19 @@ has_net_transform(PandaNode *node) const {
 ////////////////////////////////////////////////////////////////////
 void CharacterJoint::
 clear_net_transforms() {
+  NodeList::iterator ai;
+  for (ai = _net_transform_nodes.begin();
+       ai != _net_transform_nodes.end();
+       ++ai) {
+    PandaNode *node = *ai;
+
+    CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
+    if (effect != (RenderEffect *)NULL &&
+        DCAST(CharacterJointEffect, effect)->get_character() == _character) {
+      node->clear_effect(CharacterJointEffect::get_class_type());
+    }
+  }
+
   _net_transform_nodes.clear();
 }
 
@@ -231,9 +265,20 @@ clear_net_transforms() {
 //               transform from its parent.  Returns true if the node
 //               is successfully added, false if it had already been
 //               added.
+//
+//               The Character pointer should be the Character object
+//               that owns this joint; this will be used to create a
+//               CharacterJointEffect for this node.  If it is NULL,
+//               no such effect will be created.
+//
+//               A CharacterJointEffect for this joint's Character
+//               will automatically be added to the specified node.
 ////////////////////////////////////////////////////////////////////
 bool CharacterJoint::
 add_local_transform(PandaNode *node) {
+  if (_character != (Character *)NULL) {
+    node->set_effect(CharacterJointEffect::make(_character));
+  }
   return _local_transform_nodes.insert(node).second;
 }
 
@@ -245,9 +290,18 @@ add_local_transform(PandaNode *node) {
 //               transform from its parent.  Returns true if the node
 //               is successfully removed, false if it was not on the
 //               list.
+//
+//               If the node has a CharacterJointEffect that matches
+//               this joint's Character, it will be cleared.
 ////////////////////////////////////////////////////////////////////
 bool CharacterJoint::
 remove_local_transform(PandaNode *node) {
+  CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
+  if (effect != (RenderEffect *)NULL &&
+      DCAST(CharacterJointEffect, effect)->get_character() == _character) {
+    node->clear_effect(CharacterJointEffect::get_class_type());
+  }
+
   return (_local_transform_nodes.erase(node) > 0);
 }
 
@@ -272,6 +326,19 @@ has_local_transform(PandaNode *node) const {
 ////////////////////////////////////////////////////////////////////
 void CharacterJoint::
 clear_local_transforms() {
+  NodeList::iterator ai;
+  for (ai = _local_transform_nodes.begin();
+       ai != _local_transform_nodes.end();
+       ++ai) {
+    PandaNode *node = *ai;
+
+    CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
+    if (effect != (RenderEffect *)NULL &&
+        DCAST(CharacterJointEffect, effect)->get_character() == _character) {
+      node->clear_effect(CharacterJointEffect::get_class_type());
+    }
+  }
+
   _local_transform_nodes.clear();
 }
 
@@ -298,6 +365,73 @@ get_net_transform(LMatrix4f &transform) const {
   transform = _net_transform;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::get_character
+//       Access: Published
+//  Description: Returns the Character that owns this joint.
+////////////////////////////////////////////////////////////////////
+Character *CharacterJoint::
+get_character() const {
+  return _character;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::set_character
+//       Access: Private
+//  Description: Changes the Character that owns this joint.
+////////////////////////////////////////////////////////////////////
+void CharacterJoint::
+set_character(Character *character) {
+  if (character != _character) {
+
+    if (character != (Character *)NULL) {
+      // Change or set a _character pointer on each joint's exposed
+      // node.
+      NodeList::iterator ai;
+      for (ai = _net_transform_nodes.begin();
+           ai != _net_transform_nodes.end();
+           ++ai) {
+        PandaNode *node = *ai;
+        node->set_effect(CharacterJointEffect::make(character));
+      }
+      for (ai = _local_transform_nodes.begin();
+           ai != _local_transform_nodes.end();
+           ++ai) {
+        PandaNode *node = *ai;
+        node->set_effect(CharacterJointEffect::make(character));
+      }
+
+    } else {  // (character == (Character *)NULL)
+      // Clear the _character pointer on each joint's exposed node.
+      NodeList::iterator ai;
+      for (ai = _net_transform_nodes.begin();
+           ai != _net_transform_nodes.end();
+           ++ai) {
+        PandaNode *node = *ai;
+        
+        CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
+        if (effect != (RenderEffect *)NULL &&
+            DCAST(CharacterJointEffect, effect)->get_character() == _character) {
+          node->clear_effect(CharacterJointEffect::get_class_type());
+        }
+      }
+      for (ai = _local_transform_nodes.begin();
+           ai != _local_transform_nodes.end();
+           ++ai) {
+        PandaNode *node = *ai;
+        
+        CPT(RenderEffect) effect = node->get_effect(CharacterJointEffect::get_class_type());
+        if (effect != (RenderEffect *)NULL &&
+            DCAST(CharacterJointEffect, effect)->get_character() == _character) {
+          node->clear_effect(CharacterJointEffect::get_class_type());
+        }
+      }
+    }
+  }
+    
+  _character = character;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CharacterJoint::write_datagram
 //       Access: Public
@@ -305,22 +439,23 @@ get_net_transform(LMatrix4f &transform) const {
 //               the particular object to a Datagram
 ////////////////////////////////////////////////////////////////////
 void CharacterJoint::
-write_datagram(BamWriter *manager, Datagram &me)
-{
+write_datagram(BamWriter *manager, Datagram &me) {
   NodeList::iterator ni;
   MovingPartMatrix::write_datagram(manager, me);
 
+  manager->write_pointer(me, _character);
+
   me.add_uint16(_net_transform_nodes.size());
-  for(ni = _net_transform_nodes.begin(); 
-      ni != _net_transform_nodes.end(); 
-      ni++) {
+  for (ni = _net_transform_nodes.begin(); 
+       ni != _net_transform_nodes.end(); 
+       ni++) {
     manager->write_pointer(me, (*ni));
   }
 
   me.add_uint16(_local_transform_nodes.size());
-  for(ni = _local_transform_nodes.begin(); 
-      ni != _local_transform_nodes.end(); 
-      ni++) {
+  for (ni = _local_transform_nodes.begin(); 
+       ni != _local_transform_nodes.end(); 
+       ni++) {
     manager->write_pointer(me, (*ni));
   }
 
@@ -340,6 +475,10 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   int i;
   MovingPartMatrix::fillin(scan, manager);
 
+  if (manager->get_file_minor_ver() >= 4) {
+    manager->read_pointer(scan);
+  }
+
   _num_net_nodes = scan.get_uint16();
   for(i = 0; i < _num_net_nodes; i++) {
     manager->read_pointer(scan);
@@ -356,15 +495,20 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 //     Function: CharacterJoint::complete_pointers
 //       Access: Public
-//  Description: Takes in a vector of pointes to TypedWritable
+//  Description: Takes in a vector of pointers to TypedWritable
 //               objects that correspond to all the requests for
 //               pointers that this object made to BamReader.
 ////////////////////////////////////////////////////////////////////
 int CharacterJoint::
-complete_pointers(TypedWritable **p_list, BamReader* manager)
-{
+complete_pointers(TypedWritable **p_list, BamReader* manager) {
   int pi = MovingPartMatrix::complete_pointers(p_list, manager);
 
+  if (manager->get_file_minor_ver() >= 4) {
+    _character = DCAST(Character, p_list[pi++]);
+  } else {
+    _character = NULL;
+  }
+
   int i;
   for (i = 0; i < _num_net_nodes; i++) {
     add_net_transform(DCAST(PandaNode, p_list[pi++]));
@@ -383,8 +527,7 @@ complete_pointers(TypedWritable **p_list, BamReader* manager)
 //  Description: Factory method to generate a CharacterJoint object
 ////////////////////////////////////////////////////////////////////
 TypedWritable* CharacterJoint::
-make_CharacterJoint(const FactoryParams &params)
-{
+make_CharacterJoint(const FactoryParams &params) {
   CharacterJoint *me = new CharacterJoint;
   DatagramIterator scan;
   BamReader *manager;
@@ -400,8 +543,7 @@ make_CharacterJoint(const FactoryParams &params)
 //  Description: Factory method to generate a CharacterJoint object
 ////////////////////////////////////////////////////////////////////
 void CharacterJoint::
-register_with_read_factory()
-{
+register_with_read_factory() {
   BamReader::get_factory()->register_factory(get_class_type(), make_CharacterJoint);
 }
 

+ 11 - 1
panda/src/char/characterJoint.h

@@ -25,6 +25,7 @@
 #include "pandaNode.h"
 
 class JointVertexTransform;
+class Character;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : CharacterJoint
@@ -37,7 +38,8 @@ protected:
   CharacterJoint(const CharacterJoint &copy);
 
 public:
-  CharacterJoint(PartGroup *parent, const string &name,
+  CharacterJoint(Character *character,
+                 PartGroup *parent, const string &name,
                  const LMatrix4f &initial_value);
   virtual ~CharacterJoint();
 
@@ -60,7 +62,15 @@ PUBLISHED:
   void get_transform(LMatrix4f &transform) const;
   void get_net_transform(LMatrix4f &transform) const;
 
+  Character *get_character() const;
+
+private:
+  void set_character(Character *character);
+
 private:
+  // Not a reference-counted pointer.
+  Character *_character;
+
   typedef pset< PT(PandaNode) > NodeList;
   NodeList _net_transform_nodes;
   NodeList _local_transform_nodes;

+ 39 - 0
panda/src/char/characterJointEffect.I

@@ -0,0 +1,39 @@
+// Filename: characterJointEffect.I
+// Created by:  drose (26Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::Constructor
+//       Access: Private
+//  Description: Use CharacterJointEffect::make() to construct a new
+//               CharacterJointEffect object.
+////////////////////////////////////////////////////////////////////
+INLINE CharacterJointEffect::
+CharacterJointEffect() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::get_character
+//       Access: Published
+//  Description: Returns the Character that will get update() called
+//               on it when this node's relative transform is queried.
+////////////////////////////////////////////////////////////////////
+INLINE Character *CharacterJointEffect::
+get_character() const {
+  return _character;
+}

+ 239 - 0
panda/src/char/characterJointEffect.cxx

@@ -0,0 +1,239 @@
+// Filename: characterJointEffect.cxx
+// Created by:  drose (26Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "characterJointEffect.h"
+#include "cullTraverser.h"
+#include "cullTraverserData.h"
+#include "nodePath.h"
+#include "look_at.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+
+TypeHandle CharacterJointEffect::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::make
+//       Access: Published, Static
+//  Description: Constructs a new CharacterJointEffect object that
+//               references the indicated character.  When a relative
+//               get_transform() is called on the node that contains
+//               the CharacterJointEffect, it will implicitly call
+//               character->update() first.
+////////////////////////////////////////////////////////////////////
+CPT(RenderEffect) CharacterJointEffect::
+make(Character *character) {
+  CharacterJointEffect *effect = new CharacterJointEffect;
+  effect->_character = character;
+  return return_new(effect);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::safe_to_transform
+//       Access: Public, Virtual
+//  Description: Returns true if it is generally safe to transform
+//               this particular kind of RenderEffect by calling the
+//               xform() method, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool CharacterJointEffect::
+safe_to_transform() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::output
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void CharacterJointEffect::
+output(ostream &out) const {
+  out << get_type() << "(" << _character->get_name() << ")";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::has_cull_callback
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if cull_callback() has been defined.  Otherwise,
+//               returns false to indicate cull_callback() does not
+//               need to be called for this effect during the cull
+//               traversal.
+////////////////////////////////////////////////////////////////////
+bool CharacterJointEffect::
+has_cull_callback() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::cull_callback
+//       Access: Public, Virtual
+//  Description: If has_cull_callback() returns true, this function
+//               will be called during the cull traversal to perform
+//               any additional operations that should be performed at
+//               cull time.  This may include additional manipulation
+//               of render state or additional visible/invisible
+//               decisions, or any other arbitrary operation.
+//
+//               At the time this function is called, the current
+//               node's transform and state have not yet been applied
+//               to the net_transform and net_state.  This callback
+//               may modify the node_transform and node_state to apply
+//               an effective change to the render state at this
+//               level.
+////////////////////////////////////////////////////////////////////
+void CharacterJointEffect::
+cull_callback(CullTraverser *trav, CullTraverserData &data,
+              CPT(TransformState) &node_transform,
+              CPT(RenderState) &) const {
+  CPT(TransformState) dummy_transform = TransformState::make_identity();
+  adjust_transform(dummy_transform, node_transform, data.node());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::has_adjust_transform
+//       Access: Public, Virtual
+//  Description: Should be overridden by derived classes to return
+//               true if adjust_transform() has been defined, and
+//               therefore the RenderEffect has some effect on the
+//               node's apparent local and net transforms.
+////////////////////////////////////////////////////////////////////
+bool CharacterJointEffect::
+has_adjust_transform() const {
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::adjust_transform
+//       Access: Public, Virtual
+//  Description: Performs some operation on the node's apparent net
+//               and/or local transforms.  This will only be called if
+//               has_adjust_transform() is redefined to return true.
+//
+//               Both parameters are in/out.  The original transforms
+//               will be passed in, and they may (or may not) be
+//               modified in-place by the RenderEffect.
+////////////////////////////////////////////////////////////////////
+void CharacterJointEffect::
+adjust_transform(CPT(TransformState) &net_transform,
+                 CPT(TransformState) &node_transform,
+                 PandaNode *node) const {
+  _character->update();
+  node_transform = node->get_transform();
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by derived CharacterJointEffect
+//               types to return a unique number indicating whether
+//               this CharacterJointEffect is equivalent to the other one.
+//
+//               This should return 0 if the two CharacterJointEffect objects
+//               are equivalent, a number less than zero if this one
+//               should be sorted before the other one, and a number
+//               greater than zero otherwise.
+//
+//               This will only be called with two CharacterJointEffect
+//               objects whose get_type() functions return the same.
+////////////////////////////////////////////////////////////////////
+int CharacterJointEffect::
+compare_to_impl(const RenderEffect *other) const {
+  const CharacterJointEffect *ta;
+  DCAST_INTO_R(ta, other, 0);
+
+  if (_character != ta->_character) {
+    return _character < ta->_character ? -1 : 1;
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               CharacterJointEffect.
+////////////////////////////////////////////////////////////////////
+void CharacterJointEffect::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void CharacterJointEffect::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  RenderEffect::write_datagram(manager, dg);
+
+  manager->write_pointer(dg, _character);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int CharacterJointEffect::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = RenderEffect::complete_pointers(p_list, manager);
+
+  _character = DCAST(Character, p_list[pi++]);
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type CharacterJointEffect is encountered
+//               in the Bam file.  It should create the CharacterJointEffect
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *CharacterJointEffect::
+make_from_bam(const FactoryParams &params) {
+  CharacterJointEffect *effect = new CharacterJointEffect;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  effect->fillin(scan, manager);
+
+  return effect;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJointEffect::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new CharacterJointEffect.
+////////////////////////////////////////////////////////////////////
+void CharacterJointEffect::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  RenderEffect::fillin(scan, manager);
+
+  manager->read_pointer(scan);
+}

+ 100 - 0
panda/src/char/characterJointEffect.h

@@ -0,0 +1,100 @@
+// Filename: characterJointEffect.h
+// Created by:  drose (26Jul06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CHARACTERJOINTEFFECT_H
+#define CHARACTERJOINTEFFECT_H
+
+#include "pandabase.h"
+
+#include "renderEffect.h"
+#include "luse.h"
+#include "nodePath.h"
+#include "character.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : CharacterJointEffect
+// Description : This effect will be added automatically to a node by
+//               CharacterJoint::add_net_transform() and
+//               CharacterJoint::add_local_transform().
+//
+//               The effect binds the node back to the character, so
+//               that querying the relative transform of the affected
+//               node will automatically force the indicated character
+//               to be updated first.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA CharacterJointEffect : public RenderEffect {
+private:
+  INLINE CharacterJointEffect();
+
+PUBLISHED:
+  static CPT(RenderEffect) make(Character *character);
+
+  INLINE Character *get_character() const;
+
+public:
+  virtual bool safe_to_transform() const;
+  virtual void output(ostream &out) const;
+
+  virtual bool has_cull_callback() const;
+  virtual void cull_callback(CullTraverser *trav, CullTraverserData &data,
+                             CPT(TransformState) &node_transform,
+                             CPT(RenderState) &node_state) const;
+
+  virtual bool has_adjust_transform() const;
+  virtual void adjust_transform(CPT(TransformState) &net_transform,
+                                CPT(TransformState) &node_transform,
+                                PandaNode *node) const;
+
+protected:
+  virtual int compare_to_impl(const RenderEffect *other) const;
+
+private:
+  PT(Character) _character;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist,
+                                BamReader *manager);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+  
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    RenderEffect::init_type();
+    register_type(_type_handle, "CharacterJointEffect",
+                  RenderEffect::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "characterJointEffect.I"
+
+#endif
+

+ 3 - 0
panda/src/char/config_char.cxx

@@ -21,6 +21,7 @@
 #include "character.h"
 #include "characterJoint.h"
 #include "characterJointBundle.h"
+#include "characterJointEffect.h"
 #include "characterSlider.h"
 #include "characterVertexSlider.h"
 #include "jointVertexTransform.h"
@@ -62,6 +63,7 @@ init_libchar() {
   Character::init_type();
   CharacterJoint::init_type();
   CharacterJointBundle::init_type();
+  CharacterJointEffect::init_type();
   CharacterSlider::init_type();
   CharacterVertexSlider::init_type();
   JointVertexTransform::init_type();
@@ -77,6 +79,7 @@ init_libchar() {
   Character::register_with_read_factory();
   CharacterJoint::register_with_read_factory();
   CharacterJointBundle::register_with_read_factory();
+  CharacterJointEffect::register_with_read_factory();
   CharacterSlider::register_with_read_factory();
   CharacterVertexSlider::register_with_read_factory();
   JointVertexTransform::register_with_read_factory();

+ 1 - 1
panda/src/egg2pg/characterMaker.cxx

@@ -261,7 +261,7 @@ build_joint_hierarchy(EggNode *egg_node, PartGroup *part, int index) {
       LMatrix4f matf = LCAST(float, matd);
 
       CharacterJoint *joint =
-        new CharacterJoint(part, egg_group->get_name(), matf);
+        new CharacterJoint(_character_node, part, egg_group->get_name(), matf);
       index = _parts.size();
       _parts.push_back(joint);
 

+ 2 - 1
panda/src/pgraph/billboardEffect.cxx

@@ -197,7 +197,8 @@ has_adjust_transform() const {
 ////////////////////////////////////////////////////////////////////
 void BillboardEffect::
 adjust_transform(CPT(TransformState) &net_transform,
-                 CPT(TransformState) &node_transform) const {
+                 CPT(TransformState) &node_transform,
+                 PandaNode *) const {
   // A BillboardEffect can only affect the net transform when it is to
   // a particular node.  A billboard to a camera is camera-dependent,
   // of course, so it has no effect in the absence of any particular

+ 2 - 1
panda/src/pgraph/billboardEffect.h

@@ -66,7 +66,8 @@ public:
 
   virtual bool has_adjust_transform() const;
   virtual void adjust_transform(CPT(TransformState) &net_transform,
-                                CPT(TransformState) &node_transform) const;
+                                CPT(TransformState) &node_transform,
+                                PandaNode *node) const;
 
 protected:
   virtual int compare_to_impl(const RenderEffect *other) const;

+ 3 - 2
panda/src/pgraph/compassEffect.cxx

@@ -145,7 +145,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data,
 
   CPT(TransformState) true_net_transform = data.get_net_transform(trav);
   CPT(TransformState) want_net_transform = true_net_transform;
-  adjust_transform(want_net_transform, node_transform);
+  adjust_transform(want_net_transform, node_transform, data.node());
 
   // Now compute the transform that will convert true_net_transform to
   // want_transform.  This is inv(true_net_transform) * want_transform.
@@ -185,7 +185,8 @@ has_adjust_transform() const {
 ////////////////////////////////////////////////////////////////////
 void CompassEffect::
 adjust_transform(CPT(TransformState) &net_transform,
-                 CPT(TransformState) &node_transform) const {
+                 CPT(TransformState) &node_transform,
+                 PandaNode *) const {
   if (_properties == 0) {
     // Nothing to do.
     return;

+ 2 - 1
panda/src/pgraph/compassEffect.h

@@ -90,7 +90,8 @@ public:
 
   virtual bool has_adjust_transform() const;
   virtual void adjust_transform(CPT(TransformState) &net_transform,
-                                CPT(TransformState) &node_transform) const;
+                                CPT(TransformState) &node_transform,
+                                PandaNode *node) const;
 
 protected:
   virtual int compare_to_impl(const RenderEffect *other) const;

+ 4 - 3
panda/src/pgraph/nodePath.cxx

@@ -5805,11 +5805,12 @@ r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const {
   } else {
     int pipeline_stage = current_thread->get_pipeline_stage();
     CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread);
-    CPT(TransformState) transform = comp->get_node()->get_transform(current_thread);
+    PandaNode *node = comp->get_node();
+    CPT(TransformState) transform = node->get_transform(current_thread);
 
-    CPT(RenderEffects) effects = comp->get_node()->get_effects(current_thread);
+    CPT(RenderEffects) effects = node->get_effects(current_thread);
     if (effects->has_adjust_transform()) {
-      effects->adjust_transform(net_transform, transform);
+      effects->adjust_transform(net_transform, transform, node);
     }
       
     return net_transform->compose(transform);

+ 2 - 1
panda/src/pgraph/renderEffect.cxx

@@ -199,7 +199,8 @@ has_adjust_transform() const {
 //               modified in-place by the RenderEffect.
 ////////////////////////////////////////////////////////////////////
 void RenderEffect::
-adjust_transform(CPT(TransformState) &, CPT(TransformState) &) const {
+adjust_transform(CPT(TransformState) &, CPT(TransformState) &,
+                 PandaNode *) const {
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 1
panda/src/pgraph/renderEffect.h

@@ -31,6 +31,7 @@
 
 class CullTraverser;
 class CullTraverserData;
+class PandaNode;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : RenderEffect
@@ -78,7 +79,8 @@ public:
 
   virtual bool has_adjust_transform() const;
   virtual void adjust_transform(CPT(TransformState) &net_transform,
-                                CPT(TransformState) &node_transform) const;
+                                CPT(TransformState) &node_transform,
+                                PandaNode *node) const;
 
 PUBLISHED:
   INLINE int compare_to(const RenderEffect &other) const;

+ 3 - 2
panda/src/pgraph/renderEffects.cxx

@@ -520,10 +520,11 @@ cull_callback(CullTraverser *trav, CullTraverserData &data,
 ////////////////////////////////////////////////////////////////////
 void RenderEffects::
 adjust_transform(CPT(TransformState) &net_transform,
-                 CPT(TransformState) &node_transform) const {
+                 CPT(TransformState) &node_transform,
+                 PandaNode *node) const {
   Effects::const_iterator ei;
   for (ei = _effects.begin(); ei != _effects.end(); ++ei) {
-    (*ei)._effect->adjust_transform(net_transform, node_transform);
+    (*ei)._effect->adjust_transform(net_transform, node_transform, node);
   }
 }
   

+ 3 - 2
panda/src/pgraph/renderEffects.h

@@ -107,8 +107,9 @@ public:
                      CPT(RenderState) &node_state) const;
 
   INLINE bool has_adjust_transform() const;
-  virtual void adjust_transform(CPT(TransformState) &net_transform,
-                                CPT(TransformState) &node_transform) const;
+  void adjust_transform(CPT(TransformState) &net_transform,
+                        CPT(TransformState) &node_transform,
+                        PandaNode *node) const;
 
   static void init_states();
 

+ 2 - 1
panda/src/putil/bam.h

@@ -36,10 +36,11 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
-static const unsigned short _bam_minor_ver = 3;
+static const unsigned short _bam_minor_ver = 4;
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
+// Bumped to minor version 4 on 7/26/06 to add CharacterJoint::_character.
 
 
 #endif