Browse Source

add PandaNode::set_tag() and related functions

David Rose 22 years ago
parent
commit
c03d886691

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

@@ -632,6 +632,117 @@ get_lod() const {
   return *_lod;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::set_tag
+//       Access: Published
+//  Description: Associates a user-defined value with a user-defined
+//               key which is stored on the node.  This value has no
+//               meaning to Panda; but it is stored indefinitely on
+//               the node until it is requested again.  This value
+//               will be copied to the PandaNode that is created for
+//               this particular EggGroup if the egg file is loaded as
+//               a scene.
+//
+//               Each unique key stores a different string value.
+//               There is no effective limit on the number of
+//               different keys that may be stored or on the length of
+//               any one key's value.
+////////////////////////////////////////////////////////////////////
+INLINE void EggGroup::
+set_tag(const string &key, const string &value) {
+  _tag_data[key] = value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::get_tag
+//       Access: Published
+//  Description: Retrieves the user-defined value that was previously
+//               set on this node for the particular key, if any.  If
+//               no value has been previously set, returns the empty
+//               string.
+////////////////////////////////////////////////////////////////////
+INLINE string EggGroup::
+get_tag(const string &key) const {
+  TagData::const_iterator ti;
+  ti = _tag_data.find(key);
+  if (ti != _tag_data.end()) {
+    return (*ti).second;
+  }
+  return string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::has_tag
+//       Access: Published
+//  Description: Returns true if a value has been defined on this node
+//               for the particular key (even if that value is the
+//               empty string), or false if no value has been set.
+////////////////////////////////////////////////////////////////////
+INLINE bool EggGroup::
+has_tag(const string &key) const {
+  TagData::const_iterator ti;
+  ti = _tag_data.find(key);
+  return (ti != _tag_data.end());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::clear_tag
+//       Access: Published
+//  Description: Removes the value defined for this key on this
+//               particular node.  After a call to clear_tag(),
+//               has_tag() will return false for the indicated key.
+////////////////////////////////////////////////////////////////////
+INLINE void EggGroup::
+clear_tag(const string &key) {
+  _tag_data.erase(key);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::tag_begin
+//       Access: Public
+//  Description: Returns an iterator that can, in conjunction with
+//               tag_end(), be used to traverse the entire set of
+//               tag keys.  Each iterator returns a pair<string,
+//               string>.
+//
+//               This interface is not safe to use outside of
+//               PANDAEGG.DLL.
+////////////////////////////////////////////////////////////////////
+INLINE EggGroup::TagData::const_iterator EggGroup::
+tag_begin() const {
+  return _tag_data.begin();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::tag_end
+//       Access: Public
+//  Description: Returns an iterator that can, in conjunction with
+//               tag_begin(), be used to traverse the entire set of
+//               tag keys.  Each iterator returns a pair<string,
+//               string>.
+//
+//               This interface is not safe to use outside of
+//               PANDAEGG.DLL.
+////////////////////////////////////////////////////////////////////
+INLINE EggGroup::TagData::const_iterator EggGroup::
+tag_end() const {
+  return _tag_data.end();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGrop::tag_size
+//       Access: Public
+//  Description: Returns the number of elements between tag_begin()
+//               and tag_end().
+//
+//               This interface is not safe to use outside of
+//               PANDAEGG.DLL.
+////////////////////////////////////////////////////////////////////
+INLINE EggGroup::TagData::size_type EggGroup::
+tag_size() const {
+  return _tag_data.size();
+}
 
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::vref_begin

+ 13 - 0
panda/src/egg/eggGroup.cxx

@@ -65,6 +65,8 @@ operator = (const EggGroup &copy) {
   _collision_name = copy._collision_name;
   _fps = copy._fps;
 
+  _tag_data = copy._tag_data;
+
   unref_all_vertices();
   _vref = copy._vref;
 
@@ -287,6 +289,17 @@ write(ostream &out, int indent_level) const {
 
   EggRenderMode::write(out, indent_level + 2);
 
+  TagData::const_iterator ti;
+  for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
+    const string &key = (*ti).first;
+    const string &value = (*ti).second;
+
+    indent(out, indent_level + 2) << "<Tag> ";
+    enquote_string(out, key) << " {\n";
+    enquote_string(out, value, indent_level + 4) << "\n";
+    indent(out, indent_level + 2) << "}\n";
+  }
+
   // We have to write the children nodes before we write the vertex
   // references, since we might be referencing a vertex that's defined
   // in one of those children nodes!

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

@@ -40,6 +40,7 @@
 class EXPCL_PANDAEGG EggGroup : public EggGroupNode, public EggRenderMode, public EggTransform3d {
 public:
   typedef pmap<PT_EggVertex, double> VertexRef;
+  typedef pmap<string, string> TagData;
 
   // These bits are all stored somewhere in _flags.
   enum GroupType {
@@ -184,6 +185,15 @@ public:
   INLINE bool has_lod() const;
   INLINE const EggSwitchCondition &get_lod() const;
 
+  INLINE void set_tag(const string &key, const string &value);
+  INLINE string get_tag(const string &key) const;
+  INLINE bool has_tag(const string &key) const;
+  INLINE void clear_tag(const string &key);
+
+  INLINE TagData::const_iterator tag_begin() const;
+  INLINE TagData::const_iterator tag_end() const;
+  INLINE TagData::size_type tag_size() const;
+
   void ref_vertex(EggVertex *vert, double membership = 1.0);
   void unref_vertex(EggVertex *vert);
   void unref_all_vertices();
@@ -249,6 +259,7 @@ private:
   string _collision_name;
   double _fps;
   PT(EggSwitchCondition) _lod;
+  TagData _tag_data;
   VertexRef _vref;
 
 

File diff suppressed because it is too large
+ 351 - 350
panda/src/egg/lexer.cxx.prebuilt


+ 4 - 0
panda/src/egg/lexer.lxx

@@ -567,6 +567,10 @@ NUMERIC         ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
   accept();
   return TABLE_V;
 }
+"<TAG>" {
+  accept();
+  return TAG;
+}
 "<TEXLIST>" {
   accept();
   return TEXLIST;

File diff suppressed because it is too large
+ 676 - 662
panda/src/egg/parser.cxx.prebuilt


+ 81 - 79
panda/src/egg/parser.h.prebuilt

@@ -2,85 +2,87 @@
 # define BISON_Y_TAB_H
 
 # define	NUMBER	257
-# define	STRING	258
-# define	BEZIERCURVE	259
-# define	BFACE	260
-# define	BILLBOARD	261
-# define	BILLBOARDCENTER	262
-# define	BUNDLE	263
-# define	CLOSED	264
-# define	COLLIDE	265
-# define	COMMENT	266
-# define	COORDSYSTEM	267
-# define	CV	268
-# define	DART	269
-# define	DNORMAL	270
-# define	DRGBA	271
-# define	DUV	272
-# define	DXYZ	273
-# define	DCS	274
-# define	DISTANCE	275
-# define	DTREF	276
-# define	DYNAMICVERTEXPOOL	277
-# define	EXTERNAL_FILE	278
-# define	FLIGHT	279
-# define	GROUP	280
-# define	HIP	281
-# define	INTANGENT	282
-# define	JOINT	283
-# define	KNOTS	284
-# define	INCLUDE	285
-# define	INSTANCE	286
-# define	LOOP	287
-# define	MATERIAL	288
-# define	MATRIX3	289
-# define	MATRIX4	290
-# define	MODEL	291
-# define	MREF	292
-# define	NORMAL	293
-# define	NURBSCURVE	294
-# define	NURBSSURFACE	295
-# define	OBJECTTYPE	296
-# define	ORDER	297
-# define	OUTTANGENT	298
-# define	POINTLIGHT	299
-# define	POLYGON	300
-# define	REF	301
-# define	RGBA	302
-# define	ROTATE	303
-# define	ROTX	304
-# define	ROTY	305
-# define	ROTZ	306
-# define	SANIM	307
-# define	SCALAR	308
-# define	SCALE	309
-# define	SEQUENCE	310
-# define	SHADING	311
-# define	SWITCH	312
-# define	SWITCHCONDITION	313
-# define	TABLE	314
-# define	TABLE_V	315
-# define	TEXLIST	316
-# define	TEXTURE	317
-# define	TLENGTHS	318
-# define	TRANSFORM	319
-# define	TRANSLATE	320
-# define	TREF	321
-# define	TRIM	322
-# define	TXT	323
-# define	UKNOTS	324
-# define	UV	325
-# define	VKNOTS	326
-# define	VERTEX	327
-# define	VERTEXANIM	328
-# define	VERTEXPOOL	329
-# define	VERTEXREF	330
-# define	XFMANIM	331
-# define	XFMSANIM	332
-# define	START_EGG	333
-# define	START_GROUP_BODY	334
-# define	START_TEXTURE_BODY	335
-# define	START_PRIMITIVE_BODY	336
+# define	ULONG	258
+# define	STRING	259
+# define	BEZIERCURVE	260
+# define	BFACE	261
+# define	BILLBOARD	262
+# define	BILLBOARDCENTER	263
+# define	BUNDLE	264
+# define	CLOSED	265
+# define	COLLIDE	266
+# define	COMMENT	267
+# define	COORDSYSTEM	268
+# define	CV	269
+# define	DART	270
+# define	DNORMAL	271
+# define	DRGBA	272
+# define	DUV	273
+# define	DXYZ	274
+# define	DCS	275
+# define	DISTANCE	276
+# define	DTREF	277
+# define	DYNAMICVERTEXPOOL	278
+# define	EXTERNAL_FILE	279
+# define	FLIGHT	280
+# define	GROUP	281
+# define	HIP	282
+# define	INTANGENT	283
+# define	JOINT	284
+# define	KNOTS	285
+# define	INCLUDE	286
+# define	INSTANCE	287
+# define	LOOP	288
+# define	MATERIAL	289
+# define	MATRIX3	290
+# define	MATRIX4	291
+# define	MODEL	292
+# define	MREF	293
+# define	NORMAL	294
+# define	NURBSCURVE	295
+# define	NURBSSURFACE	296
+# define	OBJECTTYPE	297
+# define	ORDER	298
+# define	OUTTANGENT	299
+# define	POINTLIGHT	300
+# define	POLYGON	301
+# define	REF	302
+# define	RGBA	303
+# define	ROTATE	304
+# define	ROTX	305
+# define	ROTY	306
+# define	ROTZ	307
+# define	SANIM	308
+# define	SCALAR	309
+# define	SCALE	310
+# define	SEQUENCE	311
+# define	SHADING	312
+# define	SWITCH	313
+# define	SWITCHCONDITION	314
+# define	TABLE	315
+# define	TABLE_V	316
+# define	TAG	317
+# define	TEXLIST	318
+# define	TEXTURE	319
+# define	TLENGTHS	320
+# define	TRANSFORM	321
+# define	TRANSLATE	322
+# define	TREF	323
+# define	TRIM	324
+# define	TXT	325
+# define	UKNOTS	326
+# define	UV	327
+# define	VKNOTS	328
+# define	VERTEX	329
+# define	VERTEXANIM	330
+# define	VERTEXPOOL	331
+# define	VERTEXREF	332
+# define	XFMANIM	333
+# define	XFMSANIM	334
+# define	START_EGG	335
+# define	START_GROUP_BODY	336
+# define	START_TEXTURE_BODY	337
+# define	START_PRIMITIVE_BODY	338
 
 
 extern YYSTYPE eggyylval;

+ 6 - 1
panda/src/egg/parser.yxx

@@ -125,7 +125,7 @@ egg_cleanup_parser() {
 %token NURBSCURVE NURBSSURFACE OBJECTTYPE ORDER
 %token OUTTANGENT POINTLIGHT POLYGON REF RGBA ROTATE ROTX ROTY ROTZ
 %token SANIM SCALAR SCALE SEQUENCE SHADING SWITCH SWITCHCONDITION
-%token TABLE TABLE_V TEXLIST TEXTURE TLENGTHS TRANSFORM TRANSLATE
+%token TABLE TABLE_V TAG TEXLIST TEXTURE TLENGTHS TRANSFORM TRANSLATE
 %token TREF TRIM TXT UKNOTS UV VKNOTS VERTEX VERTEXANIM
 %token VERTEXPOOL VERTEXREF
 %token XFMANIM XFMSANIM
@@ -995,6 +995,11 @@ group_body:
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   int value = (int)$4;
   group->set_model_flag(value!=0);
+}
+        | group_body TAG optional_name '{' repeated_string '}'
+{
+  EggGroup *group = DCAST(EggGroup, egg_stack.back());
+  group->set_tag($3, $5);
 }
         | group_body TEXLIST '{' integer '}'
 {

+ 6 - 0
panda/src/egg2pg/eggLoader.cxx

@@ -1467,6 +1467,12 @@ create_group_arc(EggGroup *egg_group, PandaNode *parent, PandaNode *node) {
     _decals.insert(node);
   }
 
+  // Copy all the tags from the group onto the node.
+  EggGroup::TagData::const_iterator ti;
+  for (ti = egg_group->tag_begin(); ti != egg_group->tag_end(); ++ti) {
+    node->set_tag((*ti).first, (*ti).second);
+  }
+
   // If the group specified some property that should propagate down
   // to the leaves, we have to remember this node and apply the
   // property later, after we've created the actual geometry.

+ 59 - 0
panda/src/pgraph/nodePath.I

@@ -1124,6 +1124,65 @@ compare_to(const NodePath &other) const {
   return _head - other._head;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::set_tag
+//       Access: Published
+//  Description: Associates a user-defined value with a user-defined
+//               key which is stored on the node.  This value has no
+//               meaning to Panda; but it is stored indefinitely on
+//               the node until it is requested again.
+//
+//               Each unique key stores a different string value.
+//               There is no effective limit on the number of
+//               different keys that may be stored or on the length of
+//               any one key's value.
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+set_tag(const string &key, const string &value) {
+  nassertv_always(!is_empty());
+  node()->set_tag(key, value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::get_tag
+//       Access: Published
+//  Description: Retrieves the user-defined value that was previously
+//               set on this node for the particular key, if any.  If
+//               no value has been previously set, returns the empty
+//               string.
+////////////////////////////////////////////////////////////////////
+INLINE string NodePath::
+get_tag(const string &key) const {
+  nassertr_always(!is_empty(), string());
+  return node()->get_tag(key);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::has_tag
+//       Access: Published
+//  Description: Returns true if a value has been defined on this node
+//               for the particular key (even if that value is the
+//               empty string), or false if no value has been set.
+////////////////////////////////////////////////////////////////////
+INLINE bool NodePath::
+has_tag(const string &key) const {
+  nassertr_always(!is_empty(), false);
+  return node()->has_tag(key);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NodePath::clear_tag
+//       Access: Published
+//  Description: Removes the value defined for this key on this
+//               particular node.  After a call to clear_tag(),
+//               has_tag() will return false for the indicated key.
+////////////////////////////////////////////////////////////////////
+INLINE void NodePath::
+clear_tag(const string &key) {
+  nassertv_always(!is_empty());
+  node()->clear_tag(key);
+}
+
 
 INLINE ostream &operator << (ostream &out, const NodePath &node_path) {
   node_path.output(out);

+ 5 - 0
panda/src/pgraph/nodePath.h

@@ -519,6 +519,11 @@ PUBLISHED:
   int flatten_medium();
   int flatten_strong();
 
+  INLINE void set_tag(const string &key, const string &value);
+  INLINE string get_tag(const string &key) const;
+  INLINE bool has_tag(const string &key) const;
+  INLINE void clear_tag(const string &key);
+
   bool write_bam_file(const string &filename) const;
 
 private:

+ 67 - 0
panda/src/pgraph/pandaNode.I

@@ -137,6 +137,7 @@ CData(const PandaNode::CData &copy) :
   _state(copy._state),
   _effects(copy._effects),
   _transform(copy._transform),
+  _tag_data(copy._tag_data),
   _draw_mask(copy._draw_mask),
   _fixed_internal_bound(copy._fixed_internal_bound)
 {
@@ -657,6 +658,72 @@ clear_transform() {
   transform_changed();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::set_tag
+//       Access: Published
+//  Description: Associates a user-defined value with a user-defined
+//               key which is stored on the node.  This value has no
+//               meaning to Panda; but it is stored indefinitely on
+//               the node until it is requested again.
+//
+//               Each unique key stores a different string value.
+//               There is no effective limit on the number of
+//               different keys that may be stored or on the length of
+//               any one key's value.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+set_tag(const string &key, const string &value) {
+  CDWriter cdata(_cycler);
+  cdata->_tag_data[key] = value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::get_tag
+//       Access: Published
+//  Description: Retrieves the user-defined value that was previously
+//               set on this node for the particular key, if any.  If
+//               no value has been previously set, returns the empty
+//               string.
+////////////////////////////////////////////////////////////////////
+INLINE string PandaNode::
+get_tag(const string &key) const {
+  CDReader cdata(_cycler);
+  TagData::const_iterator ti;
+  ti = cdata->_tag_data.find(key);
+  if (ti != cdata->_tag_data.end()) {
+    return (*ti).second;
+  }
+  return string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::has_tag
+//       Access: Published
+//  Description: Returns true if a value has been defined on this node
+//               for the particular key (even if that value is the
+//               empty string), or false if no value has been set.
+////////////////////////////////////////////////////////////////////
+INLINE bool PandaNode::
+has_tag(const string &key) const {
+  CDReader cdata(_cycler);
+  TagData::const_iterator ti;
+  ti = cdata->_tag_data.find(key);
+  return (ti != cdata->_tag_data.end());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::clear_tag
+//       Access: Published
+//  Description: Removes the value defined for this key on this
+//               particular node.  After a call to clear_tag(),
+//               has_tag() will return false for the indicated key.
+////////////////////////////////////////////////////////////////////
+INLINE void PandaNode::
+clear_tag(const string &key) {
+  CDWriter cdata(_cycler);
+  cdata->_tag_data.erase(key);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::ls
 //       Access: Published

+ 78 - 0
panda/src/pgraph/pandaNode.cxx

@@ -134,6 +134,13 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
   write_up_list(_up, manager, dg);
   write_down_list(_down, manager, dg);
   write_down_list(_stashed, manager, dg);
+
+  dg.add_uint32(_tag_data.size());
+  TagData::const_iterator ti;
+  for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
+    dg.add_string((*ti).first);
+    dg.add_string((*ti).second);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -192,6 +199,16 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   fillin_up_list(_up, scan, manager);
   fillin_down_list(_down, scan, manager);
   fillin_down_list(_stashed, scan, manager);
+
+  // Read in the tag list.
+  if (manager->get_file_minor_ver() >= 4) {
+    int num_tags = scan.get_uint32();
+    for (int i = 0; i < num_tags; i++) {
+      string key = scan.get_string();
+      string value = scan.get_string();
+      _tag_data[key] = value;
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1242,6 +1259,57 @@ copy_children(PandaNode *other) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::copy_tags
+//       Access: Published
+//  Description: Copies all of the tags stored on the other node onto
+//               this node.  If a particular tag exists on both nodes,
+//               the contents of this node's value is replaced by that
+//               of the other.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+copy_tags(PandaNode *other) {
+  if (other == this) {
+    // Trivial.
+    return;
+  }
+
+  CDWriter cdataw(_cycler);
+  CDReader cdatar(other->_cycler);
+  TagData::const_iterator ti;
+  for (ti = cdatar->_tag_data.begin();
+       ti != cdatar->_tag_data.end();
+       ++ti) {
+    cdataw->_tag_data[(*ti).first] = (*ti).second;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PandaNode::list_tags
+//       Access: Published
+//  Description: Writes a list of all the tag keys assigned to the
+//               node to the indicated stream.  Writes one instance of
+//               the separator following each key (but does not write
+//               a terminal separator).  The value associated with
+//               each key is not written.
+//
+//               This is mainly for the benefit of the realtime user,
+//               to see the list of all of the associated tag keys.
+////////////////////////////////////////////////////////////////////
+void PandaNode::
+list_tags(ostream &out, const string &separator) const {
+  CDReader cdata(_cycler);
+  if (!cdata->_tag_data.empty()) {
+    TagData::const_iterator ti = cdata->_tag_data.begin();
+    out << (*ti).first;
+    ++ti;
+    while (ti != cdata->_tag_data.end()) {
+      out << separator << (*ti).first;
+      ++ti;
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PandaNode::output
 //       Access: Published, Virtual
@@ -1261,6 +1329,11 @@ void PandaNode::
 write(ostream &out, int indent_level) const {
   indent(out, indent_level) << *this;
   CDReader cdata(_cycler);
+  if (!cdata->_tag_data.empty()) {
+    out << " [";
+    list_tags(out, " ");
+    out << "]";
+  }
   if (!cdata->_transform->is_identity()) {
     out << " " << *cdata->_transform;
   }
@@ -1984,6 +2057,11 @@ void PandaNode::
 r_list_descendants(ostream &out, int indent_level) const {
   CDReader cdata(_cycler);
   indent(out, indent_level) << *this;
+  if (!cdata->_tag_data.empty()) {
+    out << " [";
+    list_tags(out, " ");
+    out << "]";
+  }
   if (!cdata->_transform->is_identity()) {
     out << " " << *cdata->_transform;
   }

+ 14 - 0
panda/src/pgraph/pandaNode.h

@@ -150,6 +150,13 @@ PUBLISHED:
   INLINE const TransformState *get_transform() const;
   INLINE void clear_transform();
 
+  INLINE void set_tag(const string &key, const string &value);
+  INLINE string get_tag(const string &key) const;
+  INLINE bool has_tag(const string &key) const;
+  INLINE void clear_tag(const string &key);
+  void copy_tags(PandaNode *other);
+  void list_tags(ostream &out, const string &separator = "\n") const;
+
   INLINE void set_draw_mask(DrawMask mask);
   INLINE DrawMask get_draw_mask() const;
 
@@ -262,6 +269,11 @@ private:
   // each NodePathComponent destructs, it removes itself from this
   // set.
   typedef pset<NodePathComponent *> Paths;
+
+  // This is used to maintain a table of keyed data on each node, for
+  // the user's purposes.
+  typedef pmap<string, string> TagData;
+
   
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
@@ -295,6 +307,8 @@ private:
     CPT(RenderEffects) _effects;
     CPT(TransformState) _transform;
 
+    TagData _tag_data;
+
     // This is the draw_mask of this particular node.
     DrawMask _draw_mask;
 

+ 7 - 1
panda/src/pgraph/sceneGraphReducer.cxx

@@ -440,10 +440,12 @@ do_flatten_child(PandaNode *grandparent_node, PandaNode *parent_node,
 
   if (new_parent != child_node) {
     new_parent->steal_children(child_node);
+    new_parent->copy_tags(child_node);
   }
 
   if (new_parent != parent_node) {
     grandparent_node->replace_child(parent_node, new_parent);
+    new_parent->copy_tags(parent_node);
   }
 
   return true;
@@ -456,7 +458,7 @@ do_flatten_child(PandaNode *grandparent_node, PandaNode *parent_node,
 //               together into a single node, leaving the resulting
 //               node attached to the parent.
 //
-//               Returns a pointer to a PandaNode the reflects the
+//               Returns a pointer to a PandaNode that reflects the
 //               combined node (which may be either of the source nodes,
 //               or a new node altogether) if the siblings are
 //               successfully collapsed, or NULL if we chickened out.
@@ -483,16 +485,20 @@ do_flatten_siblings(PandaNode *parent_node, PandaNode *child1,
   if (new_child == child1) {
     new_child->steal_children(child2);
     parent_node->remove_child(child2);
+    new_child->copy_tags(child2);
 
   } else if (new_child == child2) {
     new_child->steal_children(child1);
     parent_node->remove_child(child1);
+    new_child->copy_tags(child1);
 
   } else {
     new_child->steal_children(child1);
     new_child->steal_children(child2);
     parent_node->remove_child(child2);
     parent_node->replace_child(child1, new_child);
+    new_child->copy_tags(child1);
+    new_child->copy_tags(child2);
   }
 
   return new_child;

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

@@ -34,10 +34,11 @@ static const unsigned short _bam_major_ver = 4;
 // Bumped to major version 3 on 12/8/00 to change float64's to float32's.
 // Bumped to major version 4 on 4/10/02 to store new scene graph.
 
-static const unsigned short _bam_minor_ver = 3;
+static const unsigned short _bam_minor_ver = 4;
 // Bumped to minor version 1 on 4/10/03 to add CullFaceAttrib::reverse.
 // Bumped to minor version 2 on 4/12/03 to add num_components to texture.
-// Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel.
+// Bumped to minor version 3 on 4/15/03 to add ImageBuffer::_alpha_file_channel
+// Bumped to minor version 4 on 6/12/03 to add PandaNode::set_tag().
 
 
 #endif

Some files were not shown because too many files changed in this diff