Browse Source

robustify transform and object type interface

David Rose 23 years ago
parent
commit
efc0a0b45b

+ 25 - 0
panda/src/egg/eggGroup.I

@@ -27,6 +27,25 @@ get_group_type() const {
   return (GroupType)(_flags & F_group_type);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::is_instance_type
+//       Access: Public
+//  Description: Returns true if this group is an instance type node;
+//               i.e. it begins the root of a local coordinate space.
+//               This is not related to instancing (multiple copies of
+//               a node in a scene graph).
+//
+//               This also includes the case of the node including a
+//               billboard flag without an explicit center, which
+//               implicitly makes the node behave like an instance.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggGroup::
+is_instance_type() const {
+  return 
+    (get_group_type() == GT_instance) ||
+    (get_billboard_type() != BT_none && !has_billboard_center());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::set_billboard_type
 //       Access: Public
@@ -37,6 +56,8 @@ set_billboard_type(BillboardType type) {
   // Make sure the user didn't give us any stray bits.
   nassertv((type & ~F_billboard_type)==0);
   _flags = (_flags & ~F_billboard_type) | type;
+  // This may change the transform space of this node.
+  update_under(0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -74,6 +95,8 @@ INLINE void EggGroup::
 set_billboard_center(const LPoint3d &billboard_center) {
   _billboard_center = billboard_center;
   _flags2 |= F2_billboard_center;
+  // This may change the transform space of this node.
+  update_under(0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -84,6 +107,8 @@ set_billboard_center(const LPoint3d &billboard_center) {
 INLINE void EggGroup::
 clear_billboard_center() {
   _flags2 &= ~F2_billboard_center;
+  // This may change the transform space of this node.
+  update_under(0);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 61 - 10
panda/src/egg/eggGroup.cxx

@@ -22,9 +22,9 @@
 #include "eggBin.h"
 #include "lexerDefs.h"
 
-#include <indent.h>
-#include <string_utils.h>
-#include <lmatrix.h>
+#include "indent.h"
+#include "string_utils.h"
+#include "lmatrix.h"
 
 
 TypeHandle EggGroup::_type_handle;
@@ -119,6 +119,43 @@ set_group_type(GroupType type) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::has_object_type
+//       Access: Public
+//  Description: Returns true if the indicated object type has been
+//               added to the group, or false otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggGroup::
+has_object_type(const string &object_type) const {
+  vector_string::const_iterator oi;
+  for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
+    if (cmp_nocase_uh((*oi), object_type) == 0) {
+      return true;
+    }
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::remove_object_type
+//       Access: Public
+//  Description: Removes the first instance of the indicated object
+//               type from the group if it is present.  Returns true
+//               if the object type was found and removed, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggGroup::
+remove_object_type(const string &object_type) {
+  vector_string::iterator oi;
+  for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
+    if (cmp_nocase_uh((*oi), object_type) == 0) {
+      _object_types.erase(oi);
+      return true;
+    }
+  }
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::write
 //       Access: Public, Virtual
@@ -680,10 +717,6 @@ egg_start_parse_body() {
 ////////////////////////////////////////////////////////////////////
 void EggGroup::
 adjust_under() {
-  // Billboards without an explicit center are an implicit instance.
-  bool is_billboard_instance =
-    (get_billboard_type() != BT_none && !has_billboard_center());
-
   // If we have our own transform, it carries forward.
 
   // As of 4/18/01, this now also affects the local_coord flag, below.
@@ -699,9 +732,11 @@ adjust_under() {
       new MatrixFrame(invert(get_node_frame()));
     _vertex_to_node =
       new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
+    _node_to_vertex =
+      new MatrixFrame(get_node_frame() * get_vertex_frame_inv());
   }
 
-  if (get_group_type() == GT_instance || is_billboard_instance) {
+  if (is_instance_type()) {
     _under_flags |= UF_under_instance;
     if (_under_flags & UF_under_transform) {
       // If we've reached an instance node and we're under a
@@ -716,6 +751,7 @@ adjust_under() {
     _vertex_frame = _node_frame;
     _vertex_frame_inv = _node_frame_inv;
     _vertex_to_node = NULL;
+    _node_to_vertex = NULL;
   }
 }
 
@@ -753,7 +789,7 @@ r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
     mat1.set_row(3, LVector3d(0.0, 0.0, 0.0));
     inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
 
-    set_transform(inv1 * get_transform() * mat);
+    internal_set_transform(inv1 * get_transform() * mat);
 
     EggGroupNode::r_transform(mat1, inv1, to_cs);
   } else {
@@ -799,11 +835,26 @@ r_flatten_transforms() {
   }
 
   if (get_group_type() != GT_joint) {
-    clear_transform();
+    internal_clear_transform();
   }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::transform_changed
+//       Access: Protected, Virtual
+//  Description: This virtual method is inherited by EggTransform3d;
+//               it is called whenever the transform is changed.
+////////////////////////////////////////////////////////////////////
+void EggGroup::
+transform_changed() {
+  // Recompute all of the cached transforms at this node and below.
+  // We should probably make this smarter and do lazy evaluation of
+  // these transforms, rather than having to recompute the whole tree
+  // with every change to a parent node's transform.
+  update_under(0);
+}
+
 
 
 ////////////////////////////////////////////////////////////////////

+ 5 - 0
panda/src/egg/eggGroup.h

@@ -100,6 +100,7 @@ public:
 
   void set_group_type(GroupType type);
   INLINE GroupType get_group_type() const;
+  INLINE bool is_instance_type() const;
 
   INLINE void set_billboard_type(BillboardType type);
   INLINE BillboardType get_billboard_type() const;
@@ -136,6 +137,8 @@ public:
   INLINE void clear_object_types();
   INLINE int get_num_object_types() const;
   INLINE string get_object_type(int index) const;
+  bool has_object_type(const string &object_type) const;
+  bool remove_object_type(const string &object_type);
 
   INLINE void set_model_flag(bool flag);
   INLINE bool get_model_flag() const;
@@ -201,6 +204,8 @@ protected:
                            CoordinateSystem to_cs);
   virtual void r_flatten_transforms();
 
+  virtual void transform_changed();
+
 private:
 
   enum Flags {

+ 21 - 0
panda/src/egg/eggNode.I

@@ -212,6 +212,26 @@ get_vertex_to_node() const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::get_node_to_vertex
+//       Access: Public
+//  Description: Returns the transformation matrix suitable for
+//               converting vertices in the coordinate space of the
+//               node to the appropriate coordinate space for storing
+//               in the egg file.  This is the same thing as:
+//
+//               get_node_frame() * get_vertex_frame_inv()
+//
+////////////////////////////////////////////////////////////////////
+INLINE const LMatrix4d &EggNode::
+get_node_to_vertex() const {
+  if (_node_to_vertex == (LMatrix4d *)NULL) {
+    return LMatrix4d::ident_mat();
+  } else {
+    return *_node_to_vertex;
+  }
+}
+
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggNode::transform
@@ -259,4 +279,5 @@ transform_vertices_only(const LMatrix4d &mat) {
 INLINE void EggNode::
 flatten_transforms() {
   r_flatten_transforms();
+  update_under(0);
 }

+ 2 - 0
panda/src/egg/eggNode.cxx

@@ -244,6 +244,7 @@ update_under(int depth_offset) {
     _vertex_frame_inv = NULL;
     _node_frame_inv = NULL;
     _vertex_to_node = NULL;
+    _node_to_vertex = NULL;
   } else {
     depth = _parent->_depth + 1;
     _under_flags = _parent->_under_flags;
@@ -252,6 +253,7 @@ update_under(int depth_offset) {
     _vertex_frame_inv = _parent->_vertex_frame_inv;
     _node_frame_inv = _parent->_node_frame_inv;
     _vertex_to_node = _parent->_vertex_to_node;
+    _node_to_vertex = _parent->_node_to_vertex;
   }
 
   if (depth - _depth != depth_offset) {

+ 2 - 0
panda/src/egg/eggNode.h

@@ -56,6 +56,7 @@ public:
   INLINE const LMatrix4d &get_vertex_frame_inv() const;
   INLINE const LMatrix4d &get_node_frame_inv() const;
   INLINE const LMatrix4d &get_vertex_to_node() const;
+  INLINE const LMatrix4d &get_node_to_vertex() const;
 
   INLINE void transform(const LMatrix4d &mat);
   INLINE void transform_vertices_only(const LMatrix4d &mat);
@@ -112,6 +113,7 @@ protected:
   PT(MatrixFrame) _vertex_frame_inv;
   PT(MatrixFrame) _node_frame_inv;
   PT(MatrixFrame) _vertex_to_node;
+  PT(MatrixFrame) _node_to_vertex;
 
 
 public:

+ 37 - 2
panda/src/egg/eggTransform3d.I

@@ -90,6 +90,29 @@ INLINE EggTransform3d::Component::
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::clear_transform
+//       Access: Public
+//  Description: Resets the transform to empty, identity.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform3d::
+clear_transform() {
+  internal_clear_transform();
+  transform_changed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::add_matrix
+//       Access: Public
+//  Description: Appends an arbitrary 4x4 matrix to the current
+//               transform.
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform3d::
+add_matrix(const LMatrix4d &mat) {
+  internal_add_matrix(mat);
+  transform_changed();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTransform3d::has_transform
 //       Access: Public
@@ -111,8 +134,8 @@ has_transform() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void EggTransform3d::
 set_transform(const LMatrix4d &mat) {
-  clear_transform();
-  add_matrix(mat);
+  internal_set_transform(mat);
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -203,3 +226,15 @@ get_component_matrix(int n) const {
   nassertr(_components[n]._matrix != (LMatrix4d *)NULL, LMatrix4d::ident_mat());
   return *_components[n]._matrix;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::internal_set_transform
+//       Access: Protected
+//  Description: Sets the overall transform without calling
+//               transform_changed().
+////////////////////////////////////////////////////////////////////
+INLINE void EggTransform3d::
+internal_set_transform(const LMatrix4d &mat) {
+  internal_clear_transform();
+  internal_add_matrix(mat);
+}

+ 46 - 24
panda/src/egg/eggTransform3d.cxx

@@ -63,17 +63,6 @@ EggTransform3d::
 ~EggTransform3d() {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::clear_transform
-//       Access: Public
-//  Description: Resets the transform to empty, identity.
-////////////////////////////////////////////////////////////////////
-void EggTransform3d::
-clear_transform() {
-  _components.clear();
-  _transform = LMatrix4d::ident_mat();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: EggTransform3d::add_translate
 //       Access: Public
@@ -85,6 +74,7 @@ add_translate(const LVector3d &translate) {
   _components.push_back(Component(CT_translate));
   _components.back()._vector = new LVector3d(translate);
   _transform *= LMatrix4d::translate_mat(translate);
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -98,6 +88,7 @@ void EggTransform3d::
 add_rotx(double angle) {
   _components.push_back(Component(CT_rotx, angle));
   _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(1.0, 0.0, 0.0));
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -111,6 +102,7 @@ void EggTransform3d::
 add_roty(double angle) {
   _components.push_back(Component(CT_roty, angle));
   _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 1.0, 0.0));
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -124,6 +116,7 @@ void EggTransform3d::
 add_rotz(double angle) {
   _components.push_back(Component(CT_rotz, angle));
   _transform *= LMatrix4d::rotate_mat_normaxis(angle, LVector3d(0.0, 0.0, 1.0));
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -139,6 +132,7 @@ add_rotate(double angle, const LVector3d &axis) {
   _components.push_back(Component(CT_rotate, angle));
   _components.back()._vector = new LVector3d(normaxis);
   _transform *= LMatrix4d::rotate_mat(angle, normaxis);
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -151,6 +145,7 @@ add_rotate(double angle, const LVector3d &axis) {
 void EggTransform3d::
 add_rotate(const LQuaterniond &quat) {
   add_rotate(quat.get_angle(), quat.get_axis());
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -164,6 +159,7 @@ add_scale(const LVecBase3d &scale) {
   _components.push_back(Component(CT_scale));
   _components.back()._vector = new LVector3d(scale);
   _transform *= LMatrix4d::scale_mat(scale);
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -175,19 +171,7 @@ void EggTransform3d::
 add_uniform_scale(double scale) {
   _components.push_back(Component(CT_uniform_scale, scale));
   _transform *= LMatrix4d::scale_mat(scale);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: EggTransform3d::add_matrix
-//       Access: Public
-//  Description: Appends an arbitrary 4x4 matrix to the current
-//               transform.
-////////////////////////////////////////////////////////////////////
-void EggTransform3d::
-add_matrix(const LMatrix4d &mat) {
-  _components.push_back(Component(CT_matrix));
-  _components.back()._matrix = new LMatrix4d(mat);
-  _transform *= mat;
+  transform_changed();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -253,3 +237,41 @@ write(ostream &out, int indent_level) const {
 
   indent(out, indent_level) << "}\n";
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::internal_clear_transform
+//       Access: Public
+//  Description: Resets the transform to empty without calling
+//               transform_changed().
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+internal_clear_transform() {
+  _components.clear();
+  _transform = LMatrix4d::ident_mat();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::internal_add_matrix
+//       Access: Public
+//  Description: Appends an arbitrary 4x4 matrix to the current
+//               transform, without calling transform_changed().
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+internal_add_matrix(const LMatrix4d &mat) {
+  _components.push_back(Component(CT_matrix));
+  _components.back()._matrix = new LMatrix4d(mat);
+  _transform *= mat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggTransform3d::transform_changed
+//       Access: Protected, Virtual
+//  Description: This virtual method is called whenever the transform
+//               is changed; it is intended to provide a hook for
+//               derived classes (e.g. EggGroup) to update their
+//               internal cache appropriately.
+////////////////////////////////////////////////////////////////////
+void EggTransform3d::
+transform_changed() {
+}
+

+ 9 - 2
panda/src/egg/eggTransform3d.h

@@ -37,7 +37,7 @@ public:
   EggTransform3d &operator = (const EggTransform3d &copy);
   ~EggTransform3d();
 
-  void clear_transform();
+  INLINE void clear_transform();
 
   void add_translate(const LVector3d &translate);
   void add_rotx(double angle); 
@@ -47,7 +47,7 @@ public:
   void add_rotate(const LQuaterniond &quat);
   void add_scale(const LVecBase3d &scale);
   void add_uniform_scale(double scale);
-  void add_matrix(const LMatrix4d &mat);
+  INLINE void add_matrix(const LMatrix4d &mat);
 
   INLINE bool has_transform() const;
   INLINE void set_transform(const LMatrix4d &mat);
@@ -74,6 +74,13 @@ public:
 
   void write(ostream &out, int indent_level) const;
 
+protected:
+  void internal_clear_transform();
+  void internal_add_matrix(const LMatrix4d &mat);
+  INLINE void internal_set_transform(const LMatrix4d &mat);
+
+  virtual void transform_changed();
+
 private:
   class Component {
   public: