Browse Source

fix miscellaneous bugs

David Rose 20 years ago
parent
commit
f24c240d76

+ 3 - 2
panda/src/egg/eggBinMaker.cxx

@@ -212,9 +212,10 @@ collect_nodes(EggGroupNode *group) {
 
 
       // And remove it from the scene graph.
       // And remove it from the scene graph.
       group->erase(i);
       group->erase(i);
+    }
 
 
-    } else if (node->is_of_type(EggGroupNode::get_class_type())) {
-      // Here's a normal group node, not to be binned.  Traverse.
+    if (node->is_of_type(EggGroupNode::get_class_type())) {
+      // Recursively traverse.
       collect_nodes(DCAST(EggGroupNode, node));
       collect_nodes(DCAST(EggGroupNode, node));
     }
     }
 
 

+ 20 - 1
panda/src/egg/eggGroup.cxx

@@ -365,7 +365,7 @@ write_object_types(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::write_decal_flags
 //     Function: EggGroup::write_decal_flags
 //       Access: Public
 //       Access: Public
-//  Description: Writes the flags related to decalling, if any.
+//  Description: Writes the flags related to decaling, if any.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void EggGroup::
 void EggGroup::
 write_decal_flags(ostream &out, int indent_level) const {
 write_decal_flags(ostream &out, int indent_level) const {
@@ -544,6 +544,25 @@ determine_indexed() {
   return EggGroupNode::determine_indexed();
   return EggGroupNode::determine_indexed();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::determine_decal
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               at this level or above that has the "decal" flag
+//               set.  Returns the value of the decal flag if it
+//               is found, or false if it is not.
+//
+//               In other words, returns true if the "decal" flag is
+//               in effect for the indicated node, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggGroup::
+determine_decal() {
+  if (get_decal_flag()) {
+    return true;
+  }
+  return EggGroupNode::determine_decal();
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::ref_vertex
 //     Function: EggGroup::ref_vertex
 //       Access: Public
 //       Access: Public

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

@@ -120,6 +120,7 @@ PUBLISHED:
   virtual EggRenderMode *determine_draw_order();
   virtual EggRenderMode *determine_draw_order();
   virtual EggRenderMode *determine_bin();
   virtual EggRenderMode *determine_bin();
   virtual bool determine_indexed();
   virtual bool determine_indexed();
+  virtual bool determine_decal();
 
 
   void set_group_type(GroupType type);
   void set_group_type(GroupType type);
   INLINE GroupType get_group_type() const;
   INLINE GroupType get_group_type() const;

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

@@ -198,6 +198,26 @@ determine_indexed() {
   return _parent->determine_indexed();
   return _parent->determine_indexed();
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggNode::determine_decal
+//       Access: Public, Virtual
+//  Description: Walks back up the hierarchy, looking for an EggGroup
+//               at this level or above that has the "decal" flag
+//               set.  Returns the value of the decal flag if it
+//               is found, or false if it is not.
+//
+//               In other words, returns true if the "decal" flag is
+//               in effect for the indicated node, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool EggNode::
+determine_decal() {
+  if (_parent == (EggGroupNode *)NULL) {
+    // Too bad; we're done.
+    return false;
+  }
+  return _parent->determine_decal();
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggNode::parse_egg
 //     Function: EggNode::parse_egg

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

@@ -80,6 +80,7 @@ PUBLISHED:
   virtual EggRenderMode *determine_draw_order();
   virtual EggRenderMode *determine_draw_order();
   virtual EggRenderMode *determine_bin();
   virtual EggRenderMode *determine_bin();
   virtual bool determine_indexed();
   virtual bool determine_indexed();
+  virtual bool determine_decal();
 
 
   virtual void write(ostream &out, int indent_level) const=0;
   virtual void write(ostream &out, int indent_level) const=0;
   bool parse_egg(const string &egg_syntax);
   bool parse_egg(const string &egg_syntax);

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

@@ -238,7 +238,6 @@ egg_to_slider(const string &name) {
 CharacterJointBundle *CharacterMaker::
 CharacterJointBundle *CharacterMaker::
 make_bundle() {
 make_bundle() {
   build_joint_hierarchy(_egg_root, _skeleton_root);
   build_joint_hierarchy(_egg_root, _skeleton_root);
-  _bundle->sort_descendants();
 
 
   if (use_qpgeom) {
   if (use_qpgeom) {
     // The new, experimental Geom system.
     // The new, experimental Geom system.
@@ -251,8 +250,9 @@ make_bundle() {
     _character_node->_computed_vertices =
     _character_node->_computed_vertices =
       _comp_verts_maker.make_computed_vertices(_character_node, *this);
       _comp_verts_maker.make_computed_vertices(_character_node, *this);
   }
   }
+  _bundle->sort_descendants();
   parent_joint_nodes(_skeleton_root);
   parent_joint_nodes(_skeleton_root);
-    
+
   return _bundle;
   return _bundle;
 }
 }
 
 

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

@@ -1493,7 +1493,7 @@ separate_switches(EggNode *egg_node) {
   bool parent_has_switch = false;
   bool parent_has_switch = false;
   if (egg_node->is_of_type(EggGroup::get_class_type())) {
   if (egg_node->is_of_type(EggGroup::get_class_type())) {
     EggGroup *egg_group = DCAST(EggGroup, egg_node);
     EggGroup *egg_group = DCAST(EggGroup, egg_node);
-    parent_has_switch = egg_group->get_switch_flag();
+    parent_has_switch = egg_group->get_switch_flag() || egg_group->has_lod();
   }
   }
 
 
   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
   if (egg_node->is_of_type(EggGroupNode::get_class_type())) {
@@ -1778,7 +1778,11 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
     bool all_polysets = false;
     bool all_polysets = false;
     bool any_hidden = false;
     bool any_hidden = false;
     if (use_qpgeom) {
     if (use_qpgeom) {
-      check_for_polysets(egg_group, all_polysets, any_hidden);
+      // We don't want to ever create a GeomNode under a "decal" flag,
+      // since that can confuse the decal reparenting.
+      if (!egg_group->determine_decal()) {
+        check_for_polysets(egg_group, all_polysets, any_hidden);
+      }
     }
     }
 
 
     if (all_polysets && !any_hidden) {
     if (all_polysets && !any_hidden) {

+ 4 - 1
panda/src/gobj/qpgeom.cxx

@@ -513,7 +513,10 @@ draw(GraphicsStateGuardianBase *gsg, const qpGeomMunger *munger,
     for (pi = cdata->_primitives.begin(); 
     for (pi = cdata->_primitives.begin(); 
          pi != cdata->_primitives.end();
          pi != cdata->_primitives.end();
          ++pi) {
          ++pi) {
-      (*pi)->draw(gsg);
+      const qpGeomPrimitive *primitive = (*pi);
+      if (primitive->get_num_vertices() != 0) {
+        (*pi)->draw(gsg);
+      }
     }
     }
     gsg->end_draw_primitives();
     gsg->end_draw_primitives();
   }
   }

+ 32 - 0
panda/src/gobj/qpgeomVertexArrayFormat.I

@@ -30,6 +30,25 @@ is_registered() const {
   return _is_registered;
   return _is_registered;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::register_format
+//       Access: Published, Static
+//  Description: Adds the indicated format to the registry, if there
+//               is not an equivalent format already there; in either
+//               case, returns the pointer to the equivalent format
+//               now in the registry.
+//
+//               This is similar to
+//               GeomVertexFormat::register_format(), except that you
+//               generally need not call it explicitly.  Calling
+//               GeomVertexFormat::register_format() automatically
+//               registers all of the nested array formats.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexArrayFormat) qpGeomVertexArrayFormat::
+register_format(const qpGeomVertexArrayFormat *format) {
+  return get_registry()->register_format((qpGeomVertexArrayFormat *)format);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayFormat::get_stride
 //     Function: qpGeomVertexArrayFormat::get_stride
 //       Access: Published
 //       Access: Published
@@ -113,6 +132,19 @@ has_column(const InternalName *name) const {
   return (get_column(name) != (qpGeomVertexColumn *)NULL);
   return (get_column(name) != (qpGeomVertexColumn *)NULL);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_registry
+//       Access: Private
+//  Description: Returns the global registry object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexArrayFormat::Registry *qpGeomVertexArrayFormat::
+get_registry() {
+  if (_registry == (Registry *)NULL) {
+    make_registry();
+  }
+  return _registry;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayFormat::consider_sort_columns
 //     Function: qpGeomVertexArrayFormat::consider_sort_columns
 //       Access: Private
 //       Access: Private

+ 88 - 0
panda/src/gobj/qpgeomVertexArrayFormat.cxx

@@ -25,6 +25,7 @@
 #include "bamWriter.h"
 #include "bamWriter.h"
 #include "indirectLess.h"
 #include "indirectLess.h"
 
 
+qpGeomVertexArrayFormat::Registry *qpGeomVertexArrayFormat::_registry = NULL;
 TypeHandle qpGeomVertexArrayFormat::_type_handle;
 TypeHandle qpGeomVertexArrayFormat::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -185,6 +186,9 @@ operator = (const qpGeomVertexArrayFormat &copy) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexArrayFormat::
 qpGeomVertexArrayFormat::
 ~qpGeomVertexArrayFormat() {
 ~qpGeomVertexArrayFormat() {
+  if (is_registered()) {
+    get_registry()->unregister_format(this);
+  }
   Columns::iterator ci;
   Columns::iterator ci;
   for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
   for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
     delete (*ci);
     delete (*ci);
@@ -501,6 +505,18 @@ sort_columns() {
   sort(_columns.begin(), _columns.end(), IndirectLess<qpGeomVertexColumn>());
   sort(_columns.begin(), _columns.end(), IndirectLess<qpGeomVertexColumn>());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::make_registry
+//       Access: Private
+//  Description: Returns the global registry object.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+make_registry() {
+  if (_registry == (Registry *)NULL) {
+    _registry = new Registry;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayFormat::do_register
 //     Function: qpGeomVertexArrayFormat::do_register
 //       Access: Private
 //       Access: Private
@@ -511,6 +527,17 @@ do_register() {
   nassertv(!_is_registered);
   nassertv(!_is_registered);
   _is_registered = true;
   _is_registered = true;
 }
 }
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::do_unregister
+//       Access: Private
+//  Description: Called internally when the format is unregistered.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+do_unregister() {
+  nassertv(_is_registered);
+  _is_registered = false;
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayFormat::register_with_read_factory
 //     Function: qpGeomVertexArrayFormat::register_with_read_factory
@@ -613,3 +640,64 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   }
   }
   _columns_unsorted = false;
   _columns_unsorted = false;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Registry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::Registry::
+Registry() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Registry::register_format
+//       Access: Public
+//  Description: Adds the indicated format to the registry, if there
+//               is not an equivalent format already there; in either
+//               case, returns the pointer to the equivalent format
+//               now in the registry.
+//
+//               This must be called before a format may be used in a
+//               Geom.  After this call, you should discard the
+//               original pointer you passed in (which may or may not
+//               now be invalid) and let its reference count decrement
+//               normally; you should use only the returned value from
+//               this point on.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexArrayFormat) qpGeomVertexArrayFormat::Registry::
+register_format(qpGeomVertexArrayFormat *format) {
+  if (format->is_registered()) {
+    return format;
+  }
+
+  // Save the incoming pointer in a local PointerTo, so that if it has
+  // a zero reference count and is not added into the map below, it
+  // will be automatically deleted when this function returns.
+  PT(qpGeomVertexArrayFormat) pt_format = format;
+
+  ArrayFormats::iterator fi = _formats.insert(format).first;
+
+  qpGeomVertexArrayFormat *new_format = (*fi);
+  if (!new_format->is_registered()) {
+    new_format->do_register();
+  }
+
+  return new_format;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Registry::unregister_format
+//       Access: Public
+//  Description: Removes the indicated format from the registry.
+//               Normally this should not be done until the format is
+//               destructing.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::Registry::
+unregister_format(qpGeomVertexArrayFormat *format) {
+  nassertv(format->is_registered());
+  ArrayFormats::iterator fi = _formats.find(format);
+  nassertv(fi != _formats.end());
+  _formats.erase(fi);
+  format->do_unregister();
+}

+ 22 - 1
panda/src/gobj/qpgeomVertexArrayFormat.h

@@ -22,6 +22,7 @@
 #include "pandabase.h"
 #include "pandabase.h"
 #include "typedWritableReferenceCount.h"
 #include "typedWritableReferenceCount.h"
 #include "qpgeomVertexColumn.h"
 #include "qpgeomVertexColumn.h"
+#include "indirectCompareTo.h"
 #include "pvector.h"
 #include "pvector.h"
 #include "pmap.h"
 #include "pmap.h"
 
 
@@ -90,6 +91,7 @@ PUBLISHED:
   ~qpGeomVertexArrayFormat();
   ~qpGeomVertexArrayFormat();
 
 
   INLINE bool is_registered() const;
   INLINE bool is_registered() const;
+  INLINE static CPT(qpGeomVertexArrayFormat) register_format(const qpGeomVertexArrayFormat *format);
 
 
   INLINE int get_stride() const;
   INLINE int get_stride() const;
   INLINE void set_stride(int stride);
   INLINE void set_stride(int stride);
@@ -123,9 +125,15 @@ public:
   int compare_to(const qpGeomVertexArrayFormat &other) const;
   int compare_to(const qpGeomVertexArrayFormat &other) const;
 
 
 private:
 private:
+  class Registry;
+  INLINE static Registry *get_registry();
+  static void make_registry();
+
+  void do_register();
+  void do_unregister();
+
   INLINE void consider_sort_columns() const;
   INLINE void consider_sort_columns() const;
   void sort_columns();
   void sort_columns();
-  void do_register();
 
 
   bool _is_registered;
   bool _is_registered;
   int _stride;
   int _stride;
@@ -139,6 +147,19 @@ private:
   typedef pmap<const InternalName *, qpGeomVertexColumn *> ColumnsByName;
   typedef pmap<const InternalName *, qpGeomVertexColumn *> ColumnsByName;
   ColumnsByName _columns_by_name;
   ColumnsByName _columns_by_name;
 
 
+  // This is the global registry of all currently-in-use array formats.
+  typedef pset<qpGeomVertexArrayFormat *, IndirectCompareTo<qpGeomVertexArrayFormat> > ArrayFormats;
+  class EXPCL_PANDA Registry {
+  public:
+    Registry();
+    CPT(qpGeomVertexArrayFormat) register_format(qpGeomVertexArrayFormat *format);
+    void unregister_format(qpGeomVertexArrayFormat *format);
+
+    ArrayFormats _formats;
+  };
+
+  static Registry *_registry;
+
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

+ 2 - 3
panda/src/gobj/qpgeomVertexData.cxx

@@ -1394,10 +1394,9 @@ finalize(BamReader *manager) {
 
 
   for (size_t i = 0; i < cdata->_arrays.size(); ++i) {
   for (size_t i = 0; i < cdata->_arrays.size(); ++i) {
     CPT(qpGeomVertexArrayFormat) new_array_format = new_format->get_array(i);
     CPT(qpGeomVertexArrayFormat) new_array_format = new_format->get_array(i);
-    CPT(qpGeomVertexArrayFormat) old_array_format = _format->get_array(i);
-    nassertv(cdata->_arrays[i]->_array_format == old_array_format);
+    nassertv(cdata->_arrays[i]->_array_format->compare_to(*new_array_format) == 0);
 
 
-    manager->change_pointer(old_array_format, new_array_format);
+    manager->change_pointer(cdata->_arrays[i]->_array_format, new_array_format);
     cdata->_arrays[i]->_array_format = new_array_format;
     cdata->_arrays[i]->_array_format = new_array_format;
   }
   }
 
 

+ 3 - 3
panda/src/gobj/qpgeomVertexFormat.cxx

@@ -503,9 +503,10 @@ do_register() {
   nassertv(_columns_by_name.empty());
   nassertv(_columns_by_name.empty());
 
 
   for (int array = 0; array < (int)_arrays.size(); ++array) {
   for (int array = 0; array < (int)_arrays.size(); ++array) {
-    const qpGeomVertexArrayFormat *array_format = _arrays[array];
+    CPT(qpGeomVertexArrayFormat) array_format = _arrays[array];
     if (!array_format->is_registered()) {
     if (!array_format->is_registered()) {
-      ((qpGeomVertexArrayFormat *)array_format)->do_register();
+      array_format = qpGeomVertexArrayFormat::register_format(array_format);
+      _arrays[array] = (qpGeomVertexArrayFormat *)array_format.p();
     }
     }
 
 
     // Now add the names to the index.
     // Now add the names to the index.
@@ -580,7 +581,6 @@ do_register() {
     }
     }
   }
   }
 
 
-
   _is_registered = true;
   _is_registered = true;
 
 
   get_array_info(InternalName::get_vertex(), _vertex_array_index,
   get_array_info(InternalName::get_vertex(), _vertex_array_index,

+ 11 - 2
panda/src/gobj/texture.cxx

@@ -1460,11 +1460,20 @@ fillin(DatagramIterator &scan, BamReader *manager, bool has_rawdata) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Texture::
 void Texture::
 write_datagram(BamWriter *manager, Datagram &me) {
 write_datagram(BamWriter *manager, Datagram &me) {
-  bool has_rawdata = (bam_texture_mode == BTM_rawdata);
-
   Filename filename = get_filename();
   Filename filename = get_filename();
   Filename alpha_filename = get_alpha_filename();
   Filename alpha_filename = get_alpha_filename();
 
 
+  // Write out the texture's raw pixel data if (a) the current Bam
+  // Texture Mode requires that, or (b) there's no filename, so the
+  // file can't be loaded up from disk, but the raw pixel data is
+  // currently available in RAM.
+
+  // Otherwise, we just write out the filename, and assume whoever
+  // loads the bam file later will have access to the image file on
+  // disk.
+  bool has_rawdata = 
+    (bam_texture_mode == BTM_rawdata || (has_ram_image() && filename.empty()));
+
   switch (bam_texture_mode) {
   switch (bam_texture_mode) {
   case BTM_unchanged:
   case BTM_unchanged:
   case BTM_rawdata:
   case BTM_rawdata:

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

@@ -128,8 +128,9 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
               get_dual_transparent_state_decals() : 
               get_dual_transparent_state_decals() : 
               get_dual_transparent_state();
               get_dual_transparent_state();
             transparent_part->_state = state->compose(transparent_state);
             transparent_part->_state = state->compose(transparent_state);
-            transparent_part->munge_geom(get_geom_munger(transparent_part->_state),
-                                         traverser);
+            transparent_part->munge_geom
+              (_gsg, get_geom_munger(transparent_part->_state),
+               traverser);
             CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
             CullBin *bin = get_bin(transparent_part->_state->get_bin_index());
             nassertv(bin != (CullBin *)NULL);
             nassertv(bin != (CullBin *)NULL);
             bin->add_object(transparent_part);
             bin->add_object(transparent_part);
@@ -156,7 +157,7 @@ add_object(CullableObject *object, const CullTraverser *traverser) {
 
 
   // Munge vertices as needed for the GSG's requirements, and the
   // Munge vertices as needed for the GSG's requirements, and the
   // object's current state.
   // object's current state.
-  object->munge_geom(get_geom_munger(object->_state), traverser);
+  object->munge_geom(_gsg, get_geom_munger(object->_state), traverser);
   
   
   CullBin *bin = get_bin(object->_state->get_bin_index());
   CullBin *bin = get_bin(object->_state->get_bin_index());
   nassertv(bin != (CullBin *)NULL);
   nassertv(bin != (CullBin *)NULL);

+ 7 - 2
panda/src/pgraph/cullableObject.cxx

@@ -41,7 +41,8 @@ TypeHandle CullableObject::_type_handle;
 //               and/or its vertices.
 //               and/or its vertices.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CullableObject::
 void CullableObject::
-munge_geom(const qpGeomMunger *munger, const CullTraverser *traverser) {
+munge_geom(GraphicsStateGuardianBase *gsg,
+           const qpGeomMunger *munger, const CullTraverser *traverser) {
   if (_geom != (Geom *)NULL) {
   if (_geom != (Geom *)NULL) {
     // Temporary test and dcast until the experimental Geom rewrite
     // Temporary test and dcast until the experimental Geom rewrite
     // becomes the actual Geom rewrite.
     // becomes the actual Geom rewrite.
@@ -93,7 +94,11 @@ munge_geom(const qpGeomMunger *munger, const CullTraverser *traverser) {
     }
     }
   }
   }
   if (_next != (CullableObject *)NULL) {
   if (_next != (CullableObject *)NULL) {
-    _next->munge_geom(munger, traverser);
+    if (_next->_state != (RenderState *)NULL) {
+      _next->munge_geom(gsg, gsg->get_geom_munger(_next->_state), traverser);
+    } else {
+      _next->munge_geom(gsg, munger, traverser);
+    }
   }
   }
 }
 }
 
 

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

@@ -57,7 +57,8 @@ public:
 
 
   INLINE bool has_decals() const;
   INLINE bool has_decals() const;
 
 
-  void munge_geom(const qpGeomMunger *munger, const CullTraverser *traverser);
+  void munge_geom(GraphicsStateGuardianBase *gsg,
+                  const qpGeomMunger *munger, const CullTraverser *traverser);
   INLINE void draw(GraphicsStateGuardianBase *gsg);
   INLINE void draw(GraphicsStateGuardianBase *gsg);
 
 
 public:
 public:

+ 1 - 1
panda/src/pgraph/drawCullHandler.cxx

@@ -35,7 +35,7 @@ void DrawCullHandler::
 record_object(CullableObject *object, const CullTraverser *traverser) {
 record_object(CullableObject *object, const CullTraverser *traverser) {
   // Munge vertices as needed for the GSG's requirements, and the
   // Munge vertices as needed for the GSG's requirements, and the
   // object's current state.
   // object's current state.
-  object->munge_geom(_gsg->get_geom_munger(object->_state), traverser);
+  object->munge_geom(_gsg, _gsg->get_geom_munger(object->_state), traverser);
 
 
   // And draw the object, then dispense with it.
   // And draw the object, then dispense with it.
   draw(object, _gsg);
   draw(object, _gsg);

+ 46 - 26
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -127,23 +127,38 @@ void wglGraphicsStateGuardian::
 reset() {
 reset() {
   GLGraphicsStateGuardian::reset();
   GLGraphicsStateGuardian::reset();
 
 
-  _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
-  _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
-  _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
-  _supports_render_texture = has_extension("WGL_ARB_render_texture");
+  _supports_swap_control = has_extension("WGL_EXT_swap_control");
+
+  if (_supports_swap_control) {
+    _wglSwapIntervalEXT = 
+      (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+    if (_wglSwapIntervalEXT == NULL) {
+      wgldisplay_cat.error()
+        << "Driver claims to support WGL_EXT_swap_control extension, but does not define all functions.\n";
+      _supports_swap_control = false;
+    }
+  }
 
 
-  _wglCreatePbufferARB = 
-    (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
-  _wglGetPbufferDCARB = 
-    (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
-  _wglReleasePbufferDCARB = 
-    (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
-  _wglDestroyPbufferARB = 
-    (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
-  _wglQueryPbufferARB = 
-    (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
+  if (_supports_swap_control) {
+    // Set the video-sync setting up front, if we have the extension
+    // that supports it.
+    _wglSwapIntervalEXT(sync_video ? 1 : 0);
+  }
+
+  _supports_pbuffer = has_extension("WGL_ARB_pbuffer");
 
 
   if (_supports_pbuffer) {
   if (_supports_pbuffer) {
+    _wglCreatePbufferARB = 
+      (PFNWGLCREATEPBUFFERARBPROC)wglGetProcAddress("wglCreatePbufferARB");
+    _wglGetPbufferDCARB = 
+      (PFNWGLGETPBUFFERDCARBPROC)wglGetProcAddress("wglGetPbufferDCARB");
+    _wglReleasePbufferDCARB = 
+      (PFNWGLRELEASEPBUFFERDCARBPROC)wglGetProcAddress("wglReleasePbufferDCARB");
+    _wglDestroyPbufferARB = 
+      (PFNWGLDESTROYPBUFFERARBPROC)wglGetProcAddress("wglDestroyPbufferARB");
+    _wglQueryPbufferARB = 
+      (PFNWGLQUERYPBUFFERARBPROC)wglGetProcAddress("wglQueryPbufferARB");
+    
     if (_wglCreatePbufferARB == NULL ||
     if (_wglCreatePbufferARB == NULL ||
         _wglGetPbufferDCARB == NULL ||
         _wglGetPbufferDCARB == NULL ||
         _wglReleasePbufferDCARB == NULL ||
         _wglReleasePbufferDCARB == NULL ||
@@ -155,14 +170,16 @@ reset() {
     }
     }
   }
   }
 
 
-  _wglGetPixelFormatAttribivARB =
-    (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
-  _wglGetPixelFormatAttribfvARB =
-    (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
-  _wglChoosePixelFormatARB =
-    (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+  _supports_pixel_format = has_extension("WGL_ARB_pixel_format");
 
 
   if (_supports_pixel_format) {
   if (_supports_pixel_format) {
+    _wglGetPixelFormatAttribivARB =
+      (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribivARB");
+    _wglGetPixelFormatAttribfvARB =
+      (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress("wglGetPixelFormatAttribfvARB");
+    _wglChoosePixelFormatARB =
+      (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
+
     if (_wglGetPixelFormatAttribivARB == NULL ||
     if (_wglGetPixelFormatAttribivARB == NULL ||
         _wglGetPixelFormatAttribfvARB == NULL ||
         _wglGetPixelFormatAttribfvARB == NULL ||
         _wglChoosePixelFormatARB == NULL) {
         _wglChoosePixelFormatARB == NULL) {
@@ -172,14 +189,17 @@ reset() {
     }
     }
   }
   }
 
 
-  _wglBindTexImageARB = 
-    (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
-  _wglReleaseTexImageARB = 
-    (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
-  _wglSetPbufferAttribARB = 
-    (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetPbufferAttribARB");
+  _supports_wgl_multisample = has_extension("WGL_ARB_multisample");
+
+  _supports_render_texture = has_extension("WGL_ARB_render_texture");
 
 
   if (_supports_render_texture) {
   if (_supports_render_texture) {
+    _wglBindTexImageARB = 
+      (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress("wglBindTexImageARB");
+    _wglReleaseTexImageARB = 
+      (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress("wglReleaseTexImageARB");
+    _wglSetPbufferAttribARB = 
+      (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress("wglSetPbufferAttribARB");
     if (_wglBindTexImageARB == NULL ||
     if (_wglBindTexImageARB == NULL ||
         _wglReleaseTexImageARB == NULL ||
         _wglReleaseTexImageARB == NULL ||
         _wglSetPbufferAttribARB == NULL) {
         _wglSetPbufferAttribARB == NULL) {

+ 3 - 0
panda/src/wgldisplay/wglGraphicsStateGuardian.h

@@ -84,6 +84,9 @@ private:
   static bool _twindow_class_registered;
   static bool _twindow_class_registered;
 
 
 public:
 public:
+  bool _supports_swap_control;
+  PFNWGLSWAPINTERVALEXTPROC _wglSwapIntervalEXT;
+
   bool _supports_pbuffer;
   bool _supports_pbuffer;
   PFNWGLCREATEPBUFFERARBPROC _wglCreatePbufferARB;
   PFNWGLCREATEPBUFFERARBPROC _wglCreatePbufferARB;
   PFNWGLGETPBUFFERDCARBPROC _wglGetPbufferDCARB;
   PFNWGLGETPBUFFERDCARBPROC _wglGetPbufferDCARB;