Selaa lähdekoodia

changed CircBuffer to use STL-like interface

David Rose 24 vuotta sitten
vanhempi
sitoutus
f2eddac535
56 muutettua tiedostoa jossa 1265 lisäystä ja 254 poistoa
  1. 2 2
      panda/src/char/computedVertices.cxx
  2. 7 1
      panda/src/display/Sources.pp
  3. 2 0
      panda/src/display/display_composite1.cxx
  4. 1 0
      panda/src/display/display_composite2.cxx
  5. 27 0
      panda/src/display/geomContext.I
  6. 21 0
      panda/src/display/geomContext.cxx
  7. 75 0
      panda/src/display/geomContext.h
  8. 29 0
      panda/src/display/geomNodeContext.I
  9. 21 0
      panda/src/display/geomNodeContext.cxx
  10. 75 0
      panda/src/display/geomNodeContext.h
  11. 274 46
      panda/src/display/graphicsStateGuardian.cxx
  12. 34 2
      panda/src/display/graphicsStateGuardian.h
  13. 26 0
      panda/src/display/savedContext.I
  14. 21 0
      panda/src/display/savedContext.cxx
  15. 56 0
      panda/src/display/savedContext.h
  16. 4 4
      panda/src/display/textureContext.h
  17. 8 7
      panda/src/downloader/asyncDownloader.cxx
  18. 12 11
      panda/src/dxgsg/dxGraphicsStateGuardian.cxx
  19. 11 11
      panda/src/dxgsg/dxGraphicsStateGuardian.h
  20. 6 4
      panda/src/event/eventQueue.cxx
  21. 134 24
      panda/src/express/circBuffer.I
  22. 22 6
      panda/src/express/circBuffer.h
  23. 6 4
      panda/src/express/tokenBoard.I
  24. 11 10
      panda/src/glgsg/glGraphicsStateGuardian.cxx
  25. 11 11
      panda/src/glgsg/glGraphicsStateGuardian.h
  26. 32 0
      panda/src/gobj/drawable.cxx
  27. 4 6
      panda/src/gobj/drawable.h
  28. 110 9
      panda/src/gobj/geom.cxx
  29. 51 41
      panda/src/gobj/geom.h
  30. 2 2
      panda/src/gobj/geomLine.cxx
  31. 1 1
      panda/src/gobj/geomLine.h
  32. 2 2
      panda/src/gobj/geomLinestrip.cxx
  33. 1 1
      panda/src/gobj/geomLinestrip.h
  34. 2 2
      panda/src/gobj/geomPoint.cxx
  35. 1 1
      panda/src/gobj/geomPoint.h
  36. 2 2
      panda/src/gobj/geomPolygon.cxx
  37. 1 1
      panda/src/gobj/geomPolygon.h
  38. 2 2
      panda/src/gobj/geomQuad.cxx
  39. 1 1
      panda/src/gobj/geomQuad.h
  40. 2 2
      panda/src/gobj/geomSphere.cxx
  41. 1 1
      panda/src/gobj/geomSphere.h
  42. 2 2
      panda/src/gobj/geomSprite.cxx
  43. 1 1
      panda/src/gobj/geomSprite.h
  44. 2 2
      panda/src/gobj/geomTri.cxx
  45. 1 1
      panda/src/gobj/geomTri.h
  46. 2 2
      panda/src/gobj/geomTrifan.cxx
  47. 1 1
      panda/src/gobj/geomTrifan.h
  48. 2 2
      panda/src/gobj/geomTristrip.cxx
  49. 1 1
      panda/src/gobj/geomTristrip.h
  50. 22 11
      panda/src/gsgbase/graphicsStateGuardianBase.h
  51. 8 7
      panda/src/loader/loader.cxx
  52. 4 0
      panda/src/pstatclient/pStatProperties.cxx
  53. 2 2
      panda/src/sgattrib/drawBoundsTransition.cxx
  54. 93 5
      panda/src/sgraph/geomNode.cxx
  55. 12 0
      panda/src/sgraph/geomNode.h
  56. 1 0
      panda/src/sgraph/geomTransformer.cxx

+ 2 - 2
panda/src/char/computedVertices.cxx

@@ -213,8 +213,8 @@ update(Character *character) {
       DCAST_INTO_V(joint, character->get_part(vt._joint_index));
 
       mat =
-    joint->_initial_net_transform_inverse *
-    joint->_net_transform;
+        joint->_initial_net_transform_inverse *
+        joint->_net_transform;
     }
 
     Vertices::const_iterator vi;

+ 7 - 1
panda/src/display/Sources.pp

@@ -11,6 +11,7 @@
  
   #define SOURCES  \
      config_display.h displayRegion.I displayRegion.h  \
+     geomContext.I geomContext.h geomNodeContext.I geomNodeContext.h \
      graphicsChannel.I graphicsChannel.h graphicsLayer.I  \
      graphicsLayer.h graphicsPipe.I graphicsPipe.N graphicsPipe.h  \
      graphicsStateGuardian.I graphicsStateGuardian.N  \
@@ -20,21 +21,25 @@
      hardwareChannel.h interactiveGraphicsPipe.I  \
      interactiveGraphicsPipe.h noninteractiveGraphicsPipe.I  \
      noninteractiveGraphicsPipe.h pipeSpec.I pipeSpec.h  \
+     savedContext.I savedContext.h \
      savedFrameBuffer.I savedFrameBuffer.h textureContext.I  \
      textureContext.h  
      
  #define INCLUDED_SOURCES  \
-     config_display.cxx displayRegion.cxx graphicsChannel.cxx  \
+     config_display.cxx displayRegion.cxx \
+     geomContext.cxx geomNodeContext.cxx graphicsChannel.cxx  \
      graphicsLayer.cxx graphicsPipe.cxx graphicsStateGuardian.cxx  \
      graphicsWindow.cxx graphicsWindowInputDevice.cxx  \
      hardwareChannel.cxx interactiveGraphicsPipe.cxx  \
      noninteractiveGraphicsPipe.cxx pipeSpec.cxx  \
+     savedContext.cxx \
      savedFrameBuffer.cxx textureContext.cxx 
 
   #define INSTALL_HEADERS \
     config_display.h \
     displayRegion.I displayRegion.h displayRegionStack.I \
     displayRegionStack.h frameBufferStack.I frameBufferStack.h \
+    geomContext.I geomContext.h geomNodeContext.I geomNodeContext.h \
     graphicsChannel.I graphicsChannel.h graphicsLayer.I graphicsLayer.h \
     graphicsPipe.I graphicsPipe.h graphicsStateGuardian.I \
     graphicsStateGuardian.h graphicsWindow.I graphicsWindow.h \
@@ -42,6 +47,7 @@
     hardwareChannel.I hardwareChannel.h interactiveGraphicsPipe.I \
     interactiveGraphicsPipe.h noninteractiveGraphicsPipe.I \
     noninteractiveGraphicsPipe.h pipeSpec.I pipeSpec.h renderBuffer.h \
+    savedContext.I savedContext.h \
     savedFrameBuffer.I savedFrameBuffer.h textureContext.I \
     textureContext.h
 

+ 2 - 0
panda/src/display/display_composite1.cxx

@@ -1,5 +1,7 @@
 
 #include "displayRegion.cxx"
+#include "geomContext.cxx"
+#include "geomNodeContext.cxx"
 #include "graphicsChannel.cxx"
 #include "graphicsLayer.cxx"
 #include "graphicsPipe.cxx"

+ 1 - 0
panda/src/display/display_composite2.cxx

@@ -4,5 +4,6 @@
 #include "interactiveGraphicsPipe.cxx"
 #include "noninteractiveGraphicsPipe.cxx"
 #include "pipeSpec.cxx"
+#include "savedContext.cxx"
 #include "savedFrameBuffer.cxx"
 #include "textureContext.cxx"

+ 27 - 0
panda/src/display/geomContext.I

@@ -0,0 +1,27 @@
+// Filename: geomContext.I
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomContext::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomContext::
+GeomContext(Geom *geom) : _geom(geom) {
+}

+ 21 - 0
panda/src/display/geomContext.cxx

@@ -0,0 +1,21 @@
+// Filename: geomContext.cxx
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "geomContext.h"
+
+TypeHandle GeomContext::_type_handle;

+ 75 - 0
panda/src/display/geomContext.h

@@ -0,0 +1,75 @@
+// Filename: geomContext.h
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GEOMCONTEXT_H
+#define GEOMCONTEXT_H
+
+#include <pandabase.h>
+
+#include "savedContext.h"
+
+class Geom;
+
+////////////////////////////////////////////////////////////////////
+//       Class : GeomContext
+// Description : This is a special class object, similar to a
+//               TextureContext, that holds all the information
+//               returned by a particular GSG to cache the rendering
+//               information associated with one or more Geoms.  This
+//               is similar to, but different from, a GeomNode
+//               context, which is associated with the containing
+//               GeomNode class; a GSG might prefer to associate data
+//               with either the Geom or the GeomNode or both.
+//
+//               This allows the GSG to precompute some information
+//               necessary for drawing the Geoms as quickly as
+//               possible and reuse that information across multiple
+//               frames.  Typically, only static Geoms
+//               (e.g. nonindexed) will be assigned GeomContexts.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA GeomContext : public SavedContext {
+public:
+  INLINE GeomContext(Geom *geom);
+
+  // This cannot be a PT(Geom), because the geom and the GSG
+  // both own their GeomContexts!  That would create a circular
+  // reference count.
+  Geom *_geom;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    SavedContext::init_type();
+    register_type(_type_handle, "GeomContext",
+                  SavedContext::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 "geomContext.I"
+
+#endif
+

+ 29 - 0
panda/src/display/geomNodeContext.I

@@ -0,0 +1,29 @@
+// Filename: geomNodeContext.I
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNodeContext::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE GeomNodeContext::
+GeomNodeContext(GeomNode *node) :
+  _node(node)
+{
+}

+ 21 - 0
panda/src/display/geomNodeContext.cxx

@@ -0,0 +1,21 @@
+// Filename: geomNodeContext.cxx
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "geomNodeContext.h"
+
+TypeHandle GeomNodeContext::_type_handle;

+ 75 - 0
panda/src/display/geomNodeContext.h

@@ -0,0 +1,75 @@
+// Filename: geomNodeContext.h
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef GEOMNODECONTEXT_H
+#define GEOMNODECONTEXT_H
+
+#include <pandabase.h>
+
+#include "savedContext.h"
+
+class GeomNode;
+
+////////////////////////////////////////////////////////////////////
+//       Class : GeomNodeContext
+// Description : This is a special class object, similar to a
+//               TextureContext, that holds all the information
+//               returned by a particular GSG to cache the rendering
+//               information associated with one or more GeomNodes.
+//               This is similar to, but different from, a Geom
+//               context, which is associated with the containing Geom
+//               class; a GSG might prefer to associate data with
+//               either the Geom or the GeomNode or both.
+//
+//               This allows the GSG to precompute some information
+//               necessary for drawing the Geoms as quickly as
+//               possible and reuse that information across multiple
+//               frames.  Typically, only static Geoms
+//               (e.g. nonindexed) will be assigned GeomContexts.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA GeomNodeContext : public SavedContext {
+public:
+  INLINE GeomNodeContext(GeomNode *node);
+
+  // This cannot be a PT(GeomNode), because the geomNode and the GSG
+  // both own their GeomNodeContexts!  That would create a circular
+  // reference count.
+  GeomNode *_node;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    SavedContext::init_type();
+    register_type(_type_handle, "GeomNodeContext",
+                  SavedContext::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 "geomNodeContext.I"
+
+#endif
+

+ 274 - 46
panda/src/display/graphicsStateGuardian.cxx

@@ -29,6 +29,10 @@
 #ifndef CPPPARSER
 PStatCollector GraphicsStateGuardian::_total_texusage_pcollector("Texture usage");
 PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage:Active");
+PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms");
+PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active");
+PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes");
+PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active");
 PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory");
 PStatCollector GraphicsStateGuardian::_used_texmem_pcollector("Texture memory:In use");
 PStatCollector GraphicsStateGuardian::_texmgrmem_total_pcollector("Texture manager");
@@ -93,52 +97,6 @@ GraphicsStateGuardian::
 ~GraphicsStateGuardian() {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::release_all_textures
-//       Access: Public
-//  Description: Frees the resources for all textures associated with
-//               this GSG.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-release_all_textures() {
-  // We must get a copy of the _prepared_textures list first, because
-  // each call to release_texture() will remove that texture from the
-  // list, and we don't want to traverse a list while we're modifying
-  // it!
-
-  Textures temp = _prepared_textures;
-  for (Textures::const_iterator ti = temp.begin();
-       ti != temp.end();
-       ++ti) {
-    release_texture(*ti);
-  }
-
-  // Now that we've released all of the textures, the
-  // _prepared_textures list should have completely emptied itself.
-  nassertv(_prepared_textures.empty());
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::clear_attribute
-//       Access: Public
-//  Description: Explicitly clear the indicated attribute, specified
-//               by the TypeHandle of its associated transition.  If
-//               the attribute is not set already, this does nothing;
-//               if it is set, it resets it to its default value.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-clear_attribute(TypeHandle type) {
-  NodeAttributes::iterator ai = _state.find(type);
-  if (ai != _state.end()) {
-    // The state is already set; get the initial value and reset it.
-    PT(NodeAttribute) initial = (*ai).second->make_initial();
-    initial->issue(this);
-
-    // Now remove the state entry from the set.
-    _state.erase(ai);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::reset
 //       Access: Public, Virtual
@@ -421,6 +379,163 @@ enable_frame_clear(bool clear_color, bool clear_depth) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::release_all_textures
+//       Access: Public
+//  Description: Frees the resources for all textures associated with
+//               this GSG.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+release_all_textures() {
+  // We must get a copy of the _prepared_textures list first, because
+  // each call to release_texture() will remove that texture from the
+  // list, and we don't want to traverse a list while we're modifying
+  // it!
+
+  Textures temp = _prepared_textures;
+  for (Textures::const_iterator ti = temp.begin();
+       ti != temp.end();
+       ++ti) {
+    release_texture(*ti);
+  }
+
+  // Now that we've released all of the textures, the
+  // _prepared_textures list should have completely emptied itself.
+  nassertv(_prepared_textures.empty());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::release_all_geoms
+//       Access: Public
+//  Description: Frees the resources for all Geoms and GeomNodes
+//               associated with this GSG.  Warning!  This may make
+//               the Geoms unrenderable, if the Panda-level
+//               information has been deleted.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+release_all_geoms() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::clear_attribute
+//       Access: Public
+//  Description: Explicitly clear the indicated attribute, specified
+//               by the TypeHandle of its associated transition.  If
+//               the attribute is not set already, this does nothing;
+//               if it is set, it resets it to its default value.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+clear_attribute(TypeHandle type) {
+  NodeAttributes::iterator ai = _state.find(type);
+  if (ai != _state.end()) {
+    // The state is already set; get the initial value and reset it.
+    PT(NodeAttribute) initial = (*ai).second->make_initial();
+    initial->issue(this);
+
+    // Now remove the state entry from the set.
+    _state.erase(ai);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::prepare_texture
+//       Access: Public, Virtual
+//  Description: Prepares the indicated texture for retained-mode
+//               rendering.  In the future, this texture may be
+//               applied simply by calling apply_texture() with the
+//               value returned by this function.
+////////////////////////////////////////////////////////////////////
+TextureContext *GraphicsStateGuardian::
+prepare_texture(Texture *) {
+  return (TextureContext *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::apply_texture
+//       Access: Public, Virtual
+//  Description: Applies the texture previously indicated via a call
+//               to prepare_texture() to the graphics state, so that
+//               geometry rendered in the future will be rendered with
+//               the given texture.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+apply_texture(TextureContext *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::release_texture
+//       Access: Public, Virtual
+//  Description: Frees the resources previously allocated via a call
+//               to prepare_texture(), including deleting the
+//               TextureContext itself, if necessary.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+release_texture(TextureContext *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::prepare_geom_node
+//       Access: Public, Virtual
+//  Description: Prepares the indicated GeomNode for retained-mode
+//               rendering.  If this function returns non-NULL, the
+//               value returned will be passed back to a future call
+//               to draw_geom_node(), which is expected to draw the
+//               contents of the node.
+////////////////////////////////////////////////////////////////////
+GeomNodeContext *GraphicsStateGuardian::
+prepare_geom_node(GeomNode *) {
+  return (GeomNodeContext *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_geom_node
+//       Access: Public, Virtual
+//  Description: Draws a GeomNode previously indicated by a call to
+//               prepare_geom_node().
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_geom_node(GeomNode *node, GeomNodeContext *) {
+  int num_geoms = node->get_num_geoms();
+  for (int i = 0; i < num_geoms; i++) {
+    node->get_geom(i)->draw(this);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::release_geom_node
+//       Access: Public, Virtual
+//  Description: Frees the resources previously allocated via a call
+//               to prepare_geom_node(), including deleting the
+//               GeomNodeContext itself, if necessary.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+release_geom_node(GeomNodeContext *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::prepare_geom
+//       Access: Public, Virtual
+//  Description: Prepares the indicated Geom for retained-mode
+//               rendering.  The value returned by this function will
+//               be passed back into future calls to draw_tristrip(),
+//               etc., along with the Geom pointer.
+////////////////////////////////////////////////////////////////////
+GeomContext *GraphicsStateGuardian::
+prepare_geom(Geom *) {
+  return (GeomContext *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::release_geom
+//       Access: Public, Virtual
+//  Description: Frees the resources previously allocated via a call
+//               to prepare_geom(), including deleting the GeomContext
+//               itself, if necessary.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+release_geom(GeomContext *) {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::wants_normals
 //       Access: Public, Virtual
@@ -517,6 +632,86 @@ unmark_prepared_texture(TextureContext *tc) {
   return removed;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::mark_prepared_geom
+//       Access: Protected
+//  Description: This is intended to be called from within
+//               prepare_geom().  It adds the indicated GeomContext
+//               pointer to the _prepared_geoms set, and returns true
+//               if it was successfully added (i.e. it was not already
+//               in the set).
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+mark_prepared_geom(GeomContext *gc) {
+  bool prepared = _prepared_geoms.insert(gc).second;
+#ifdef DO_PSTATS
+  if (prepared) {
+    _total_geom_pcollector.add_level(1);
+  }
+#endif
+  return prepared;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::unmark_prepared_geom
+//       Access: Protected
+//  Description: This is intended to be called from within
+//               release_geom().  It removes the indicated GeomContext
+//               pointer from the _prepared_geoms set, and returns
+//               true if it was successfully removed (i.e. it had been
+//               in the set).
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+unmark_prepared_geom(GeomContext *gc) {
+  bool removed = (_prepared_geoms.erase(gc) != 0);
+#ifdef DO_PSTATS
+  if (removed) {
+    _total_geom_pcollector.sub_level(1);
+  }
+#endif
+  return removed;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::mark_prepared_geom_node
+//       Access: Protected
+//  Description: This is intended to be called from within
+//               prepare_geom_node().  It adds the indicated
+//               GeomNodeContext pointer to the _prepared_geom_nodes
+//               set, and returns true if it was successfully added
+//               (i.e. it was not already in the set).
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+mark_prepared_geom_node(GeomNodeContext *gnc) {
+  bool prepared = _prepared_geom_nodes.insert(gnc).second;
+#ifdef DO_PSTATS
+  if (prepared) {
+    _total_geom_node_pcollector.add_level(1);
+  }
+#endif
+  return prepared;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::unmark_prepared_geom_node
+//       Access: Protected
+//  Description: This is intended to be called from within
+//               release_geom_node().  It removes the indicated
+//               GeomNodeContext pointer from the _prepared_geom_nodes
+//               set, and returns true if it was successfully removed
+//               (i.e. it had been in the set).
+////////////////////////////////////////////////////////////////////
+bool GraphicsStateGuardian::
+unmark_prepared_geom_node(GeomNodeContext *gnc) {
+  bool removed = (_prepared_geom_nodes.erase(gnc) != 0);
+#ifdef DO_PSTATS
+  if (removed) {
+    _total_geom_node_pcollector.sub_level(1);
+  }
+#endif
+  return removed;
+}
+
 #ifdef DO_PSTATS
 
 ////////////////////////////////////////////////////////////////////
@@ -529,6 +724,8 @@ void GraphicsStateGuardian::
 init_frame_pstats() {
   _current_textures.clear();
   _active_texusage_pcollector.clear_level();
+  _total_geom_pcollector.clear_level();
+  _total_geom_node_pcollector.clear_level();
 
   // Also clear out our other counters while we're here.
   _vertices_tristrip_pcollector.clear_level();
@@ -560,6 +757,37 @@ add_to_texture_record(TextureContext *tc) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::add_to_geom_record
+//       Access: Protected
+//  Description: Records that the indicated Geom has been drawn this
+//               frame.  This function is only used to update the
+//               PStats current_texmem collector; it gets compiled out
+//               if we aren't using PStats.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+add_to_geom_record(GeomContext *gc) {
+  if (gc != (GeomContext *)NULL && _current_geoms.insert(gc).second) {
+    _active_geom_pcollector.add_level(1);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::add_to_geom_node_record
+//       Access: Protected
+//  Description: Records that the indicated GeomNode has been drawn
+//               this frame.  This function is only used to update the
+//               PStats current_texmem collector; it gets compiled out
+//               if we aren't using PStats.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+add_to_geom_node_record(GeomNodeContext *gnc) {
+  if (gnc != (GeomNodeContext *)NULL && 
+      _current_geom_nodes.insert(gnc).second) {
+    _active_geom_node_pcollector.add_level(1);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::record_state_change
 //       Access: Protected

+ 34 - 2
panda/src/display/graphicsStateGuardian.h

@@ -79,10 +79,22 @@ PUBLISHED:
 
   void enable_frame_clear(bool clear_color, bool clear_depth);
   void release_all_textures();
+  void release_all_geoms();
 
   void clear_attribute(TypeHandle type);
 
 public:
+  virtual TextureContext *prepare_texture(Texture *tex);
+  virtual void apply_texture(TextureContext *tc);
+  virtual void release_texture(TextureContext *tc);
+
+  virtual GeomNodeContext *prepare_geom_node(GeomNode *node);
+  virtual void draw_geom_node(GeomNode *node, GeomNodeContext *gnc);
+  virtual void release_geom_node(GeomNodeContext *gnc);
+
+  virtual GeomContext *prepare_geom(Geom *geom);
+  virtual void release_geom(GeomContext *gc);
+
   virtual void clear(const RenderBuffer &buffer)=0;
   virtual void clear(const RenderBuffer &buffer, const DisplayRegion* region)=0;
 
@@ -148,18 +160,28 @@ protected:
 
   bool mark_prepared_texture(TextureContext *tc);
   bool unmark_prepared_texture(TextureContext *tc);
+  bool mark_prepared_geom(GeomContext *gc);
+  bool unmark_prepared_geom(GeomContext *gc);
+  bool mark_prepared_geom_node(GeomNodeContext *gnc);
+  bool unmark_prepared_geom_node(GeomNodeContext *gnc);
 
 #ifdef DO_PSTATS
   // These functions are used to update the active texture memory
   // usage record (and other frame-based measurements) in Pstats.
   void init_frame_pstats();
   void add_to_texture_record(TextureContext *tc);
+  void add_to_geom_record(GeomContext *gc);
+  void add_to_geom_node_record(GeomNodeContext *gnc);
   void record_state_change(TypeHandle type);
   pset<TextureContext *> _current_textures;
+  pset<GeomContext *> _current_geoms;
+  pset<GeomNodeContext *> _current_geom_nodes;
 #else
   INLINE void init_frame_pstats() { }
   INLINE void add_to_texture_record(TextureContext *) { }
-  INLINE void record_state_change(TypeHandle type) { }
+  INLINE void add_to_geom_record(GeomContext *) { }
+  INLINE void add_to_geom_node_record(GeomNodeContext *) { }
+  INLINE void record_state_change(TypeHandle) { }
   INLINE void count_node(Node *) { }
 #endif
 
@@ -192,6 +214,10 @@ public:
   // Statistics
   static PStatCollector _total_texusage_pcollector;
   static PStatCollector _active_texusage_pcollector;
+  static PStatCollector _total_geom_pcollector;
+  static PStatCollector _active_geom_pcollector;
+  static PStatCollector _total_geom_node_pcollector;
+  static PStatCollector _active_geom_node_pcollector;
   static PStatCollector _total_texmem_pcollector;
   static PStatCollector _used_texmem_pcollector;
   static PStatCollector _texmgrmem_total_pcollector;
@@ -208,8 +234,14 @@ public:
   static PStatCollector _geom_nodes_pcollector;
 
 private:
+  // NOTE: on win32 another DLL (e.g. libpandadx.dll) cannot access
+  // these sets directly due to exported template issue
   typedef pset<TextureContext *> Textures;
-  Textures _prepared_textures;  // NOTE: on win32 another DLL (e.g. libpandadx.dll) cannot access set directly due to exported template issue
+  Textures _prepared_textures;  
+  typedef pset<GeomContext *> Geoms;
+  Geoms _prepared_geoms;  
+  typedef pset<GeomNodeContext *> GeomNodes;
+  GeomNodes _prepared_geom_nodes;  
 
 public:
   void traverse_prepared_textures(bool (*pertex_callbackfn)(TextureContext *,void *),void *callback_arg);

+ 26 - 0
panda/src/display/savedContext.I

@@ -0,0 +1,26 @@
+// Filename: savedContext.I
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////////////////////
+//     Function: SavedContext::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE SavedContext::
+SavedContext() {
+}

+ 21 - 0
panda/src/display/savedContext.cxx

@@ -0,0 +1,21 @@
+// Filename: savedContext.cxx
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "savedContext.h"
+
+TypeHandle SavedContext::_type_handle;

+ 56 - 0
panda/src/display/savedContext.h

@@ -0,0 +1,56 @@
+// Filename: savedContext.h
+// Created by:  drose (11Jun01)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef SAVEDCONTEXT_H
+#define SAVEDCONTEXT_H
+
+#include <pandabase.h>
+
+#include <typedObject.h>
+
+////////////////////////////////////////////////////////////////////
+//       Class : SavedContext
+// Description : This is the base class for both a TextureContext and
+//               a GeomContext.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA SavedContext : public TypedObject {
+public:
+  INLINE SavedContext();
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedObject::init_type();
+    register_type(_type_handle, "SavedContext",
+                  TypedObject::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 "savedContext.I"
+
+#endif
+

+ 4 - 4
panda/src/display/textureContext.h

@@ -21,7 +21,7 @@
 
 #include <pandabase.h>
 
-#include <typedObject.h>
+#include "savedContext.h"
 
 class Texture;
 
@@ -38,7 +38,7 @@ class Texture;
 //               internal handle for the texture and store it here.
 //               The texture stores all of these handles internally.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA TextureContext : public TypedObject {
+class EXPCL_PANDA TextureContext : public SavedContext {
 public:
   INLINE TextureContext(Texture *tex);
 
@@ -54,9 +54,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    TypedObject::init_type();
+    SavedContext::init_type();
     register_type(_type_handle, "TextureContext",
-                  TypedObject::get_class_type());
+                  SavedContext::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();

+ 8 - 7
panda/src/downloader/asyncDownloader.cxx

@@ -324,7 +324,7 @@ request_download(const string &file_name, const Filename &file_dest,
     _lock.lock();
 #endif
 
-      if (_token_board->_waiting.is_full()) {
+      if (_token_board->_waiting.full()) {
         downloader_cat.error()
           << "Downloader::request_download() - Too many pending requests\n";
         return 0;
@@ -338,7 +338,7 @@ request_download(const string &file_name, const Filename &file_dest,
       tok = new DownloaderToken(_next_token++, file_name, file_dest,
                 event_name, first_byte, last_byte, total_bytes,
                                         partial_content, sync);
-      _token_board->_waiting.insert(tok);
+      _token_board->_waiting.push_back(tok);
 
 #ifdef HAVE_IPC
       _request_cond->signal();
@@ -348,7 +348,7 @@ request_download(const string &file_name, const Filename &file_dest,
   } else {
     // If we're not running asynchronously, process the load request
     // directly now.
-    if (_token_board->_waiting.is_full()) {
+    if (_token_board->_waiting.full()) {
       downloader_cat.error()
         << "Downloader::request_download() - Too many pending requests\n";
       return 0;
@@ -361,7 +361,7 @@ request_download(const string &file_name, const Filename &file_dest,
     tok = new DownloaderToken(_next_token++, file_name, file_dest,
                 event_name, first_byte, last_byte, total_bytes,
                                         partial_content, sync);
-    _token_board->_waiting.insert(tok);
+    _token_board->_waiting.push_back(tok);
     process_request();
   }
 
@@ -384,8 +384,9 @@ process_request() {
   }
 
   // If there is actually a request token - process it
-  while (!_token_board->_waiting.is_empty()) {
-    PT(DownloaderToken) tok = _token_board->_waiting.extract();
+  while (!_token_board->_waiting.empty()) {
+    PT(DownloaderToken) tok = _token_board->_waiting.front();
+    _token_board->_waiting.pop_front();
     int ret = download(tok->_file_name, tok->_file_dest, tok->_event_name,
                  tok->_first_byte, tok->_last_byte, tok->_total_bytes,
                  tok->_partial_content, tok->_sync, tok->_id);
@@ -393,7 +394,7 @@ process_request() {
     PT_Event return_event = new Event(tok->_event_name);
     return_event->add_parameter(EventParameter((int)tok->_id));
     if (ret == DS_success) {
-      _token_board->_done.insert(tok);
+      _token_board->_done.push_back(tok);
       return_event->add_parameter(EventParameter(DS_success));
 
       // Throw a "done" event now.

+ 12 - 11
panda/src/dxgsg/dxGraphicsStateGuardian.cxx

@@ -1170,7 +1170,7 @@ draw_prim_inner_loop(int nVerts, const Geom *geom, DWORD perFlags) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_point(const GeomPoint *geom) {
+draw_point(GeomPoint *geom, GeomContext *gc) {
     activate();
 
 #ifdef GSG_VERBOSE
@@ -1314,7 +1314,7 @@ draw_point(const GeomPoint *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_line(const GeomLine* geom) {
+draw_line(GeomLine* geom, GeomContext *gc) {
     activate();
 
 #ifdef GSG_VERBOSE
@@ -1425,7 +1425,7 @@ draw_line(const GeomLine* geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_linestrip(const GeomLinestrip* geom) {
+draw_linestrip(GeomLinestrip* geom, GeomContext *gc) {
     activate();
 
 #ifdef GSG_VERBOSE
@@ -1585,7 +1585,7 @@ struct draw_sprite_vertex_less {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_sprite(const GeomSprite *geom) {
+draw_sprite(GeomSprite *geom, GeomContext *gc) {
 
     // this is a little bit of a mess, but it's ok.  Here's the deal:
     // we want to draw, and draw quickly, an arbitrarily large number
@@ -1909,7 +1909,7 @@ draw_sprite(const GeomSprite *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_polygon(const GeomPolygon *geom) {
+draw_polygon(GeomPolygon *geom, GeomContext *gc) {
     activate();
 
 #ifdef GSG_VERBOSE
@@ -1990,7 +1990,7 @@ draw_polygon(const GeomPolygon *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_tri(const GeomTri *geom) {
+draw_tri(GeomTri *geom, GeomContext *gc) {
     // activate();
 
 #ifdef GSG_VERBOSE
@@ -2290,7 +2290,7 @@ draw_tri(const GeomTri *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_quad(const GeomQuad *geom) {
+draw_quad(GeomQuad *geom, GeomContext *gc) {
     activate();
 
 #if 1
@@ -2359,7 +2359,7 @@ draw_quad(const GeomQuad *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_tristrip(const GeomTristrip *geom) {
+draw_tristrip(GeomTristrip *geom, GeomContext *gc) {
 
 #ifdef GSG_VERBOSE
     dxgsg_cat.debug() << "draw_tristrip()" << endl;
@@ -2375,7 +2375,7 @@ draw_tristrip(const GeomTristrip *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_trifan(const GeomTrifan *geom) {
+draw_trifan(GeomTrifan *geom, GeomContext *gc) {
 
 #ifdef GSG_VERBOSE
     dxgsg_cat.debug() << "draw_trifan()" << endl;
@@ -2391,7 +2391,7 @@ draw_trifan(const GeomTrifan *geom) {
 //  Description: handles trifans and tristrips
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_multitri(const Geom *geom, D3DPRIMITIVETYPE trilisttype) {
+draw_multitri(Geom *geom, D3DPRIMITIVETYPE trilisttype) {
 
     int nPrims = geom->get_num_prims();
     const int *pLengthArr = geom->get_lengths();
@@ -3000,7 +3000,7 @@ GenerateSphere(void *pVertexSpace,DWORD dwVertSpaceByteSize,
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian::
-draw_sphere(const GeomSphere *geom) {
+draw_sphere(GeomSphere *geom, GeomContext *gc) {
 
 #define SPHERE_NUMSLICES 16
 #define SPHERE_NUMSTACKS 10
@@ -5340,6 +5340,7 @@ void DXGraphicsStateGuardian::
 dx_cleanup() {
 
     release_all_textures();
+    release_all_geoms();
 
     // Do a safe check for releasing the D3DDEVICE. RefCount should be zero.
     if (_d3dDevice!=NULL) {

+ 11 - 11
panda/src/dxgsg/dxGraphicsStateGuardian.h

@@ -103,16 +103,16 @@ public:
                    const AllAttributesWrapper &initial_state,
                    const AllTransitionsWrapper &net_trans);
 
-  virtual void draw_point(const GeomPoint *geom);
-  virtual void draw_line(const GeomLine *geom);
-  virtual void draw_linestrip(const GeomLinestrip *geom);
-  virtual void draw_sprite(const GeomSprite *geom);
-  virtual void draw_polygon(const GeomPolygon *geom);
-  virtual void draw_quad(const GeomQuad *geom);
-  virtual void draw_tri(const GeomTri *geom);
-  virtual void draw_tristrip(const GeomTristrip *geom);
-  virtual void draw_trifan(const GeomTrifan *geom);
-  virtual void draw_sphere(const GeomSphere *geom);
+  virtual void draw_point(GeomPoint *geom, GeomContext *gc);
+  virtual void draw_line(GeomLine *geom, GeomContext *gc);
+  virtual void draw_linestrip(GeomLinestrip *geom, GeomContext *gc);
+  virtual void draw_sprite(GeomSprite *geom, GeomContext *gc);
+  virtual void draw_polygon(GeomPolygon *geom, GeomContext *gc);
+  virtual void draw_quad(GeomQuad *geom, GeomContext *gc);
+  virtual void draw_tri(GeomTri *geom, GeomContext *gc);
+  virtual void draw_tristrip(GeomTristrip *geom, GeomContext *gc);
+  virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
+  virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual void apply_texture(TextureContext *tc);
@@ -264,7 +264,7 @@ protected:
 
   void draw_prim_inner_loop(int nVerts, const Geom *geom, DWORD perFlags);
   size_t draw_prim_setup(const Geom *geom) ;
-  void draw_multitri(const Geom *geom, D3DPRIMITIVETYPE tri_id);
+  void draw_multitri(Geom *geom, D3DPRIMITIVETYPE tri_id);
 
 #ifdef DO_PSTATS
   void report_texmgr_stats();

+ 6 - 4
panda/src/event/eventQueue.cxx

@@ -50,11 +50,11 @@ queue_event(CPT_Event event) {
 #ifdef HAVE_IPC
   mutex_lock lock(_lock);
 #endif
-  if (_queue.is_full()) {
+  if (_queue.full()) {
     event_cat.error()
       << "Ignoring event " << *event << "; event queue full.\n";
   } else {
-    _queue.insert(event);
+    _queue.push_back(event);
     if (event_cat.is_spam() || event_cat.is_debug()) {
       if (event->get_name() == "NewFrame") {
         // Don't bother us with this particularly spammy event.
@@ -75,7 +75,7 @@ queue_event(CPT_Event event) {
 ////////////////////////////////////////////////////////////////////
 bool EventQueue::
 is_queue_empty() const {
-  return _queue.is_empty();
+  return _queue.empty();
 }
 
 
@@ -88,7 +88,9 @@ CPT_Event EventQueue::
 dequeue_event() {
   // We need no mutex protection here, as long as there is only one
   // thread extracting events.  The magic of circular buffers.
-  return _queue.extract();
+  CPT_Event result = _queue.front();
+  _queue.pop_front();
+  return result;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 134 - 24
panda/src/express/circBuffer.I

@@ -33,54 +33,130 @@ CircBuffer() {
   _in = _out = 0;
 }
 
-
 ////////////////////////////////////////////////////////////////////
-//     Function: CircBuffer::is_empty
+//     Function: CircBuffer::Destructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
 template<class Thing, int max_size>
-INLINE bool CircBuffer<Thing, max_size>::
-is_empty() const {
-  return _in == _out;
+INLINE CircBuffer<Thing, max_size>::
+~CircBuffer() {
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::size
+//       Access: Public
+//  Description: Returns the number of items currently in the buffer.
+//               This can safely be called without synchronization
+//               from either the reader or the writer thread, but the
+//               size may of course vary without warning after the
+//               call.
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE int CircBuffer<Thing, max_size>::
+size() const {
+  int diff = _in - _out;
+  return (diff >= 0) ? diff : max_size + 1 - diff;
+}
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CircBuffer::is_full
+//     Function: CircBuffer::empty
 //       Access: Public
-//  Description:
+//  Description: Returns true if the buffer is empty.  It is safe to
+//               call this without synchronization primitives from
+//               either the reader or the writer thread, but the
+//               result may vary without warning after the call.
 ////////////////////////////////////////////////////////////////////
 template<class Thing, int max_size>
 INLINE bool CircBuffer<Thing, max_size>::
-is_full() const {
-  return _in == _out-1 || (_in==max_size && _out==0);
+empty() const {
+  return _in == _out;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::full
+//       Access: Public
+//  Description: Returns true if the buffer is full; if this is true,
+//               push_back() will fail.  It is safe to call this
+//               without synchronization primitives from either the
+//               reader or the writer thread, but the result may vary
+//               without warning after the call.
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE bool CircBuffer<Thing, max_size>::
+full() const {
+  //  return _in == _out-1 || (_in==max_size && _out==0);
+  return ((_in + 1) % (max_size + 1)) == _out;
+}
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CircBuffer::peek
+//     Function: CircBuffer::front
 //       Access: Public
-//  Description:
+//  Description: Returns a reference to the first item in the queue.
+//               It is invalid to call this if empty() is true.  It is
+//               safe to call this without synchronization only from
+//               the reading thread: the thread that calls pop_front().
 ////////////////////////////////////////////////////////////////////
 template<class Thing, int max_size>
 INLINE const Thing &CircBuffer<Thing, max_size>::
-peek() const {
-  nassertr(!is_empty(), *(new Thing));
+front() const {
+  nassertr(!empty(), _array[0]);
   return _array[_out];
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::front
+//       Access: Public
+//  Description: Returns a reference to the first item in the queue.
+//               It is invalid to call this if empty() is true.  It is
+//               safe to call this without synchronization only from
+//               the reading thread: the thread that calls pop_front().
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE Thing &CircBuffer<Thing, max_size>::
+front() {
+  nassertr(!empty(), _array[0]);
+  return _array[_out];
+}
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CircBuffer::extract
+//     Function: CircBuffer::operator []
 //       Access: Public
-//  Description:
+//  Description: Returns the nth element in the buffer.  It is safe to
+//               call this without synchronization only from the
+//               reading thread: the thread that calls pop_front().
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE const Thing &CircBuffer<Thing, max_size>::
+operator[] (int n) const {
+  nassertr(!empty(), _array[0]);
+  return _array[(_out + n) % (max_size + 1)];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::operator []
+//       Access: Public
+//  Description: Returns the nth element in the buffer.  It is safe to
+//               call this without synchronization only from the
+//               reading thread: the thread that calls pop_front().
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE Thing &CircBuffer<Thing, max_size>::
+operator[] (int n) {
+  nassertr(!empty(), _array[0]);
+  return _array[(_out + n) % (max_size + 1)];
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::pop_front
+//       Access: Public
+//  Description: Removes the first item from the buffer.
 ////////////////////////////////////////////////////////////////////
 template<class Thing, int max_size>
-INLINE Thing CircBuffer<Thing, max_size>::
-extract() {
-  nassertr(!is_empty(), Thing());
-  Thing temp = _array[_out];
+INLINE void CircBuffer<Thing, max_size>::
+pop_front() {
+  nassertv(!empty());
 
   // We need to clear out the old element to force its destructor to
   // be called; it might be important.  This will generate yet another
@@ -89,19 +165,53 @@ extract() {
   _array[_out] = Thing();
 
   _out = (_out+1)%(max_size+1);
-  return temp;
 }
 
 
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::back
+//       Access: Public
+//  Description: Returns a reference to the last item in the queue.
+//               It is invalid to call this if empty() is true.  It is
+//               safe to call this without synchronization primitives
+//               only from the writing thread: the thread that calls
+//               push_back().
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE const Thing &CircBuffer<Thing, max_size>::
+back() const {
+  nassertr(!empty(), _array[0]);
+  return _array[(_in + max_size) % (max_size + 1)];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CircBuffer::back
+//       Access: Public
+//  Description: Returns a reference to the last item in the queue.
+//               It is invalid to call this if empty() is true.  It is
+//               safe to call this without synchronization primitives
+//               only from the writing thread: the thread that calls
+//               push_back().
+////////////////////////////////////////////////////////////////////
+template<class Thing, int max_size>
+INLINE Thing &CircBuffer<Thing, max_size>::
+back() {
+  nassertr(!empty(), _array[0]);
+  return _array[(_in + max_size) % (max_size + 1)];
+}
+
 ////////////////////////////////////////////////////////////////////
-//     Function: CircBuffer::insert
+//     Function: CircBuffer::push_back
 //       Access: Public
-//  Description:
+//  Description: Adds an item to the end of the buffer.  This may fail
+//               if full() is true.
 ////////////////////////////////////////////////////////////////////
 template<class Thing, int max_size>
 INLINE void CircBuffer<Thing, max_size>::
-insert(const Thing &t) {
-  if (is_full()) {
+push_back(const Thing &t) {
+  if (full()) {
     express_cat.error()
       << "Circular buffer is full; cannot add requests.\n";
   } else {

+ 22 - 6
panda/src/express/circBuffer.h

@@ -35,16 +35,32 @@ template<class Thing, int max_size>
 class CircBuffer {
 public:
   INLINE CircBuffer();
+  INLINE ~CircBuffer();
 
-  INLINE bool is_empty() const;
-  INLINE bool is_full() const;
+  // Methods that are safe to call without synchronization primitives
+  // from either thread.
+  INLINE int size() const;
 
-  INLINE const Thing &peek() const;
-  INLINE Thing extract();
+  // Methods that are safe to call without synchronization primitives
+  // only from the reader thread.
+  INLINE bool empty() const;
 
-  INLINE void insert(const Thing &t);
+  INLINE const Thing &front() const;
+  INLINE Thing &front();
+  INLINE void pop_front();
 
-protected:
+  INLINE const Thing &operator[] (int n) const;
+  INLINE Thing &operator[] (int n);
+
+  // Methods that are safe to call without synchronization primitives
+  // only from the writer thread.
+  INLINE bool full() const;
+
+  INLINE const Thing &back() const;
+  INLINE Thing &back();
+  INLINE void push_back(const Thing &t);
+
+private:
   Thing _array[max_size+1];
   int _in, _out;
 };

+ 6 - 4
panda/src/express/tokenBoard.I

@@ -29,8 +29,9 @@ is_done_token(int id) {
   // to do this since we can only examine tokens on the head of the
   // done list, and the token we're looking for might not be at the
   // head.
-  while (!_done.is_empty()) {
-    _really_done.push_back(_done.extract());
+  while (!_done.empty()) {
+    _really_done.push_back(_done.front());
+    _done.pop_front();
   }
 
   // Now we can search really_done for our desired id.
@@ -57,8 +58,9 @@ get_done_token(int id) {
   // to do this since we can only examine tokens on the head of the
   // done list, and the token we're looking for might not be at the
   // head.
-  while (!_done.is_empty()) {
-    _really_done.push_back(_done.extract());
+  while (!_done.empty()) {
+    _really_done.push_back(_done.front());
+    _done.pop_front();
   }
 
   // Now we can search really_done for our desired id.

+ 11 - 10
panda/src/glgsg/glGraphicsStateGuardian.cxx

@@ -190,6 +190,7 @@ GLGraphicsStateGuardian::
 ~GLGraphicsStateGuardian() {
   free_pointers();
   release_all_textures();
+  release_all_geoms();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -720,7 +721,7 @@ render_subgraph(RenderTraverser *traverser, Node *subgraph,
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_point(const GeomPoint *geom) {
+draw_point(GeomPoint *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -779,7 +780,7 @@ draw_point(const GeomPoint *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_line(const GeomLine* geom) {
+draw_line(GeomLine *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -840,7 +841,7 @@ draw_line(const GeomLine* geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_linestrip(const GeomLinestrip* geom) {
+draw_linestrip(GeomLinestrip *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -940,7 +941,7 @@ struct draw_sprite_vertex_less {
 };
 
 void GLGraphicsStateGuardian::
-draw_sprite(const GeomSprite *geom) {
+draw_sprite(GeomSprite *geom, GeomContext *) {
   // this is a little bit of a mess, but it's ok.  Here's the deal:
   // we want to draw, and draw quickly, an arbitrarily large number
   // of sprites all facing the screen.  Performing the billboard math
@@ -1226,7 +1227,7 @@ draw_sprite(const GeomSprite *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_polygon(const GeomPolygon *geom) {
+draw_polygon(GeomPolygon *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -1299,7 +1300,7 @@ draw_polygon(const GeomPolygon *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_tri(const GeomTri *geom) {
+draw_tri(GeomTri *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -1367,7 +1368,7 @@ draw_tri(const GeomTri *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_quad(const GeomQuad *geom) {
+draw_quad(GeomQuad *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -1435,7 +1436,7 @@ draw_quad(const GeomQuad *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_tristrip(const GeomTristrip *geom) {
+draw_tristrip(GeomTristrip *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -1525,7 +1526,7 @@ draw_tristrip(const GeomTristrip *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_trifan(const GeomTrifan *geom) {
+draw_trifan(GeomTrifan *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE
@@ -1616,7 +1617,7 @@ draw_trifan(const GeomTrifan *geom) {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GLGraphicsStateGuardian::
-draw_sphere(const GeomSphere *geom) {
+draw_sphere(GeomSphere *geom, GeomContext *) {
   //  activate();
 
 #ifdef GSG_VERBOSE

+ 11 - 11
panda/src/glgsg/glGraphicsStateGuardian.h

@@ -87,16 +87,16 @@ public:
                                const AllAttributesWrapper &initial_state,
                                const AllTransitionsWrapper &net_trans);
 
-  virtual void draw_point(const GeomPoint *geom);
-  virtual void draw_line(const GeomLine *geom);
-  virtual void draw_linestrip(const GeomLinestrip *geom);
-  virtual void draw_sprite(const GeomSprite *geom);
-  virtual void draw_polygon(const GeomPolygon *geom);
-  virtual void draw_quad(const GeomQuad *geom);
-  virtual void draw_tri(const GeomTri *geom);
-  virtual void draw_tristrip(const GeomTristrip *geom);
-  virtual void draw_trifan(const GeomTrifan *geom);
-  virtual void draw_sphere(const GeomSphere *geom);
+  virtual void draw_point(GeomPoint *geom, GeomContext *gc);
+  virtual void draw_line(GeomLine *geom, GeomContext *gc);
+  virtual void draw_linestrip(GeomLinestrip *geom, GeomContext *gc);
+  virtual void draw_sprite(GeomSprite *geom, GeomContext *gc);
+  virtual void draw_polygon(GeomPolygon *geom, GeomContext *gc);
+  virtual void draw_quad(GeomQuad *geom, GeomContext *gc);
+  virtual void draw_tri(GeomTri *geom, GeomContext *gc);
+  virtual void draw_tristrip(GeomTristrip *geom, GeomContext *gc);
+  virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
+  virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual void apply_texture(TextureContext *tc);
@@ -111,7 +111,7 @@ public:
 
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb);
   virtual void texture_to_pixel_buffer(TextureContext *tc, PixelBuffer *pb,
-                                const DisplayRegion *dr);
+                                       const DisplayRegion *dr);
 
   virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr);
   virtual void copy_pixel_buffer(PixelBuffer *pb, const DisplayRegion *dr,

+ 32 - 0
panda/src/gobj/drawable.cxx

@@ -20,6 +20,38 @@
 
 TypeHandle dDrawable::_type_handle;
 
+////////////////////////////////////////////////////////////////////
+//     Function: Drawable::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+dDrawable::
+dDrawable() : WritableConfigurable() {
+  MemoryUsage::update_type(this, this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Drawable::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+dDrawable::
+~dDrawable() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Drawable::draw
+//       Access: Public, Virtual
+//  Description: Actually draws the Drawable with the indicated GSG.
+//               At this level, this doesn't do very much.
+////////////////////////////////////////////////////////////////////
+void dDrawable::
+draw(GraphicsStateGuardianBase *) { 
+  if (is_dirty()) {
+    config(); 
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Drawable::propagate_stale_bound
 //       Access: Protected, Virtual

+ 4 - 6
panda/src/gobj/drawable.h

@@ -46,15 +46,13 @@ class BamWriter;
 //               to their variable names
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA dDrawable : public ReferenceCount, public WritableConfigurable,
-                  public BoundedObject {
+                              public BoundedObject {
 public:
 
-  dDrawable() : WritableConfigurable() {
-    MemoryUsage::update_type(this, this);
-  }
-  virtual ~dDrawable() { }
+  dDrawable();
+  virtual ~dDrawable();
 
-  virtual void draw(GraphicsStateGuardianBase *) { if (is_dirty()) config(); }
+  virtual void draw(GraphicsStateGuardianBase *);
 
 protected:
   virtual void propagate_stale_bound();

+ 110 - 9
panda/src/gobj/geom.cxx

@@ -142,6 +142,8 @@ ostream &operator << (ostream &out, GeomAttrType t) {
 ////////////////////////////////////////////////////////////////////
 Geom::
 Geom(void) : dDrawable() {
+  _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+  _prepared_context = (GeomContext *)NULL;
   init();
 }
 
@@ -152,6 +154,8 @@ Geom(void) : dDrawable() {
 ////////////////////////////////////////////////////////////////////
 Geom::
 Geom(const Geom& copy) : dDrawable() {
+  _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+  _prepared_context = (GeomContext *)NULL;
   *this = copy;
 }
 
@@ -161,7 +165,8 @@ Geom(const Geom& copy) : dDrawable() {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 Geom::
-~Geom(void) {
+~Geom() {
+  unprepare();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -192,8 +197,8 @@ operator = (const Geom &copy) {
   _get_color = copy._get_color;
   _get_texcoord = copy._get_texcoord;
 
-  if (copy.is_dirty())
-    make_dirty();
+  mark_bound_stale();
+  make_dirty();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -376,13 +381,30 @@ get_tris() const {
   return PTA_ushort();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::draw
+//       Access: Public, Virtual
+//  Description: Actually draws the Geom with the indicated GSG.
+////////////////////////////////////////////////////////////////////
+void Geom::
+draw(GraphicsStateGuardianBase *gsg) {
+  if (is_dirty()) {
+    config(); 
+  }
+  if (_prepared_gsg == gsg) {
+    draw_immediate(gsg, _prepared_context);
+  } else {
+    draw_immediate(gsg, (GeomContext *)NULL);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::config
-//       Access: Public
+//       Access: Public, Virtual
 //  Description: Configure rendering based on current settings
 ////////////////////////////////////////////////////////////////////
 void Geom::
-config(void) {
+config() {
   WritableConfigurable::config();
 
   // Only per vertex binding makes any sense
@@ -417,6 +439,9 @@ config(void) {
   } else {
     _get_color = get_color_noop;
   }
+
+  // Mark the Geom as needing to be prepared again.
+  unprepare();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -448,12 +473,86 @@ output(ostream &out) const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: Geom::init
+//     Function: Geom::prepare
+//       Access: Public
+//  Description: Creates a context for the Geom on the particular
+//               GSG, if it does not already exist.  Returns the new
+//               (or old) GeomContext.
+//
+//               If the given GeomContext pointer is non-NULL, it will
+//               be passed to the GSG, which may or may not choose to
+//               extend the existing GeomContext, or create a totally
+//               new one.
+////////////////////////////////////////////////////////////////////
+GeomContext *Geom::
+prepare(GraphicsStateGuardianBase *gsg) {
+  if (gsg != _prepared_gsg) {
+    GeomContext *gc = gsg->prepare_geom(this);
+    if (gc != (GeomContext *)NULL) {
+      unprepare();
+      _prepared_context = gc;
+      _prepared_gsg = gsg;
+    }
+    return gc;
+  }
+
+  return _prepared_context;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::unprepare
 //       Access: Public
+//  Description: Frees the context allocated on all GSG's for which
+//               the geom has been declared.
+////////////////////////////////////////////////////////////////////
+void Geom::
+unprepare() {
+  if (_prepared_gsg != (GraphicsStateGuardianBase *)NULL) {
+    _prepared_gsg->release_geom(_prepared_context);
+    _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+    _prepared_context = (GeomContext *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::unprepare
+//       Access: Public
+//  Description: Frees the geom context only on the indicated GSG,
+//               if it exists there.
+////////////////////////////////////////////////////////////////////
+void Geom::
+unprepare(GraphicsStateGuardianBase *gsg) {
+  if (_prepared_gsg == gsg) {
+    _prepared_gsg->release_geom(_prepared_context);
+    _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+    _prepared_context = (GeomContext *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::clear_gsg
+//       Access: Public
+//  Description: Removes the indicated GSG from the Geom's known
+//               GSG's, without actually releasing the geom on that
+//               GSG.  This is intended to be called only from
+//               GSG::release_geom(); it should never be called by
+//               user code.
+////////////////////////////////////////////////////////////////////
+void Geom::
+clear_gsg(GraphicsStateGuardianBase *gsg) {
+  if (_prepared_gsg == gsg) {
+    _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+    _prepared_context = (GeomContext *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::init
+//       Access: Protected
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void Geom::
-init(void) {
+init() {
   int i;
 
   _coords.clear();
@@ -779,10 +878,12 @@ write_verbose(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::get_min_max
 //       Access: Public
-//  Description:
+//  Description: Expands min and max, if necessary, to include the
+//               complete bounding rectangle that encloses all the
+//               vertices.
 ////////////////////////////////////////////////////////////////////
 void Geom::
-get_min_max(Vertexf& min, Vertexf& max) const {
+get_min_max(Vertexf &min, Vertexf &max) const {
   int numv = _coords.size();
 
   for (int i = 0; i < numv; i++) {

+ 51 - 41
panda/src/gobj/geom.h

@@ -113,11 +113,11 @@ public:
   typedef const Colorf &GetNextColor(ColorIterator &);
 
 
-  Geom( void );
-  Geom( const Geom& copy );
-  ~Geom( void );
+  Geom();
+  Geom(const Geom &copy);
+  ~Geom();
 
-  void operator = ( const Geom &copy );
+  void operator = (const Geom &copy);
   virtual Geom *make_copy() const=0;
 
 PUBLISHED:
@@ -127,51 +127,49 @@ PUBLISHED:
 
 public:
   // From parent dDrawable
-  virtual void draw(GraphicsStateGuardianBase *gsg) {
-    dDrawable::draw(gsg); draw_immediate(gsg);
-  }
+  virtual void draw(GraphicsStateGuardianBase *gsg);
 
   // From parent Configurable
-  virtual void config( void );
+  virtual void config();
 
   // Immediate mode drawing functions - issue graphics commands
-  virtual void draw_immediate(GraphicsStateGuardianBase *) const = 0;
-  virtual void print_draw_immediate( void ) const = 0;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) = 0;
+  virtual void print_draw_immediate() const = 0;
 
 public:
 
-  void get_min_max( Vertexf& min, Vertexf& max ) const;
+  void get_min_max(Vertexf &min, Vertexf &max) const;
 
 
-  void set_coords( const PTA_Vertexf &coords,
-                   GeomBindType bind,
-                   const PTA_ushort &vindex =
-                   PTA_ushort() );
-  void set_normals( const PTA_Normalf &norms,
-                    GeomBindType bind,
-                    const PTA_ushort &nindex =
-                    PTA_ushort() );
-  void set_colors( const PTA_Colorf &colors,
+  void set_coords(const PTA_Vertexf &coords,
+                  GeomBindType bind,
+                  const PTA_ushort &vindex =
+                  PTA_ushort());
+  void set_normals(const PTA_Normalf &norms,
                    GeomBindType bind,
-                   const PTA_ushort &cindex =
-                   PTA_ushort() );
-  void set_texcoords( const PTA_TexCoordf &texcoords,
-                      GeomBindType bind,
-                      const PTA_ushort &tindex =
-                      PTA_ushort() );
-
-  void get_coords( PTA_Vertexf &coords,
-                   GeomBindType &bind,
-                   PTA_ushort &vindex) const;
-  void get_normals( PTA_Normalf &norms,
-                    GeomBindType &bind,
-                    PTA_ushort &nindex) const;
-  void get_colors( PTA_Colorf &colors,
+                   const PTA_ushort &nindex =
+                   PTA_ushort());
+  void set_colors(const PTA_Colorf &colors,
+                  GeomBindType bind,
+                  const PTA_ushort &cindex =
+                  PTA_ushort());
+  void set_texcoords(const PTA_TexCoordf &texcoords,
+                     GeomBindType bind,
+                     const PTA_ushort &tindex =
+                     PTA_ushort());
+
+  void get_coords(PTA_Vertexf &coords,
+                  GeomBindType &bind,
+                  PTA_ushort &vindex) const;
+  void get_normals(PTA_Normalf &norms,
                    GeomBindType &bind,
-                   PTA_ushort &cindex) const;
-  void get_texcoords( PTA_TexCoordf &texcoords,
-                      GeomBindType &bind,
-                      PTA_ushort &tindex) const;
+                   PTA_ushort &nindex) const;
+  void get_colors(PTA_Colorf &colors,
+                  GeomBindType &bind,
+                  PTA_ushort &cindex) const;
+  void get_texcoords(PTA_TexCoordf &texcoords,
+                     GeomBindType &bind,
+                     PTA_ushort &tindex) const;
 
 PUBLISHED:
   INLINE GeomBindType get_binding(int attr) const;
@@ -186,7 +184,7 @@ PUBLISHED:
 
 public:
   INLINE void set_num_prims(int num);
-  INLINE int get_num_prims(void) const;
+  INLINE int get_num_prims() const;
 
   INLINE void set_lengths(const PTA_int &lengths);
   INLINE PTA_int get_lengths() const;
@@ -219,9 +217,13 @@ public:
   INLINE ColorIterator make_color_iterator() const;
   INLINE const Colorf &get_next_color(ColorIterator &citerator) const;
 
-protected:
+  GeomContext *prepare(GraphicsStateGuardianBase *gsg);
+  void unprepare();
+  void unprepare(GraphicsStateGuardianBase *gsg);
+  void clear_gsg(GraphicsStateGuardianBase *gsg);
 
-  void init( void );
+protected:
+  void init();
   virtual void recompute_bound();
 
 protected:
@@ -246,6 +248,14 @@ protected:
   GetNextTexCoord *_get_texcoord;
   GetNextColor *_get_color;
 
+  // Unlike a Texture, a Geom only stores the pointer to one GSG that
+  // it has been prepared into.  If it is prepared into another GSG,
+  // it automatically unprepares itself from the first one.  This is
+  // intended to reduce memory overhead that would otherwise be
+  // required to support a little-used feature (having two
+  // simultaneous GSG's).
+  GraphicsStateGuardianBase *_prepared_gsg;
+  GeomContext *_prepared_context;
 
 public:
   //static void register_with_read_factory(void);

+ 2 - 2
panda/src/gobj/geomLine.cxx

@@ -48,8 +48,8 @@ make_copy() const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomLine::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_line(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_line(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomLine.h

@@ -31,7 +31,7 @@ public:
   GeomLine( void ) : Geom() { _width = 1.0; }
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate( void ) const { }
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 2;

+ 2 - 2
panda/src/gobj/geomLinestrip.cxx

@@ -49,8 +49,8 @@ make_copy() const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomLinestrip::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_linestrip(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_linestrip(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomLinestrip.h

@@ -31,7 +31,7 @@ public:
   GeomLinestrip(void) : Geom() { _width = 1.0; }
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate( void ) const { }
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   // Undefined for this type of primitive
   virtual int get_num_vertices_per_prim() const {

+ 2 - 2
panda/src/gobj/geomPoint.cxx

@@ -57,8 +57,8 @@ print_draw_immediate(void) const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomPoint::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_point(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_point(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomPoint.h

@@ -31,7 +31,7 @@ public:
   virtual Geom *make_copy() const;
 
   virtual void print_draw_immediate() const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 1;

+ 2 - 2
panda/src/gobj/geomPolygon.cxx

@@ -57,8 +57,8 @@ print_draw_immediate(void) const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomPolygon::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_polygon(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_polygon(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomPolygon.h

@@ -30,7 +30,7 @@ public:
   GeomPolygon() : Geom() { }
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate() const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 0;

+ 2 - 2
panda/src/gobj/geomQuad.cxx

@@ -58,8 +58,8 @@ print_draw_immediate(void) const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomQuad::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_quad(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_quad(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomQuad.h

@@ -30,7 +30,7 @@ public:
   GeomQuad() { }
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate() const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 4;

+ 2 - 2
panda/src/gobj/geomSphere.cxx

@@ -40,8 +40,8 @@ make_copy() const {
 }
 
 void GeomSphere::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_sphere(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_sphere(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomSphere.h

@@ -42,7 +42,7 @@ public:
   GeomSphere() : Geom() { }
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate() const { }
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 2;

+ 2 - 2
panda/src/gobj/geomSprite.cxx

@@ -75,8 +75,8 @@ print_draw_immediate(void) const {
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomSprite::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_sprite(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_sprite(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomSprite.h

@@ -33,7 +33,7 @@ public:
 
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate() const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const { return 1; }
   virtual int get_num_more_vertices_than_components() const { return 0; }

+ 2 - 2
panda/src/gobj/geomTri.cxx

@@ -183,8 +183,8 @@ print_draw_immediate(void) const
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomTri::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_tri(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_tri(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomTri.h

@@ -30,7 +30,7 @@ public:
   GeomTri() { }
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate() const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 3;

+ 2 - 2
panda/src/gobj/geomTrifan.cxx

@@ -199,8 +199,8 @@ print_draw_immediate( void ) const
 //  Description:
 ////////////////////////////////////////////////////////////////////
 void GeomTrifan::
-draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_trifan(this);
+draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_trifan(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomTrifan.h

@@ -32,7 +32,7 @@ public:
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate( void ) const;
   int get_num_tris( void ) const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 0;

+ 2 - 2
panda/src/gobj/geomTristrip.cxx

@@ -272,8 +272,8 @@ void GeomTristrip::print_draw_immediate( void ) const
 //       Access:
 //  Description:
 ////////////////////////////////////////////////////////////////////
-void GeomTristrip::draw_immediate(GraphicsStateGuardianBase *gsg) const {
-  gsg->draw_tristrip(this);
+void GeomTristrip::draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) {
+  gsg->draw_tristrip(this, gc);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/gobj/geomTristrip.h

@@ -31,7 +31,7 @@ public:
   virtual Geom *make_copy() const;
   virtual void print_draw_immediate() const;
   int get_num_tris() const;
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg) const;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
 
   virtual int get_num_vertices_per_prim() const {
     return 0;

+ 22 - 11
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -30,6 +30,10 @@
 class RenderBuffer;
 class GraphicsWindow;
 
+class GeomContext;
+class GeomNodeContext;
+class GeomNode;
+class Geom;
 class GeomPoint;
 class GeomLine;
 class GeomLinestrip;
@@ -111,21 +115,28 @@ public:
   // inconvenient to declare each of those types to be friends of this
   // class.
 
-  virtual void draw_point(const GeomPoint *geom)=0;
-  virtual void draw_line(const GeomLine *geom)=0;
-  virtual void draw_linestrip(const GeomLinestrip *geom)=0;
-  virtual void draw_sprite(const GeomSprite *geom)=0;
-  virtual void draw_polygon(const GeomPolygon *geom)=0;
-  virtual void draw_quad(const GeomQuad *geom)=0;
-  virtual void draw_tri(const GeomTri *geom)=0;
-  virtual void draw_tristrip(const GeomTristrip *geom)=0;
-  virtual void draw_trifan(const GeomTrifan *geom)=0;
-  virtual void draw_sphere(const GeomSphere *geom)=0;
-
   virtual TextureContext *prepare_texture(Texture *tex)=0;
   virtual void apply_texture(TextureContext *tc)=0;
   virtual void release_texture(TextureContext *tc)=0;
 
+  virtual GeomNodeContext *prepare_geom_node(GeomNode *node)=0;
+  virtual void draw_geom_node(GeomNode *node, GeomNodeContext *gnc)=0;
+  virtual void release_geom_node(GeomNodeContext *gnc)=0;
+
+  virtual GeomContext *prepare_geom(Geom *geom)=0;
+  virtual void release_geom(GeomContext *gc)=0;
+
+  virtual void draw_point(GeomPoint *geom, GeomContext *gc)=0;
+  virtual void draw_line(GeomLine *geom, GeomContext *gc)=0;
+  virtual void draw_linestrip(GeomLinestrip *geom, GeomContext *gc)=0;
+  virtual void draw_sprite(GeomSprite *geom, GeomContext *gc)=0;
+  virtual void draw_polygon(GeomPolygon *geom, GeomContext *gc)=0;
+  virtual void draw_quad(GeomQuad *geom, GeomContext *gc)=0;
+  virtual void draw_tri(GeomTri *geom, GeomContext *gc)=0;
+  virtual void draw_tristrip(GeomTristrip *geom, GeomContext *gc)=0;
+  virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc)=0;
+  virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0;
+
   virtual void copy_texture(TextureContext *tc, const DisplayRegion *dr)=0;
   virtual void copy_texture(TextureContext *tc, const DisplayRegion *dr,
                             const RenderBuffer &rb)=0;

+ 8 - 7
panda/src/loader/loader.cxx

@@ -149,7 +149,7 @@ request_load(const Filename &filename, const string &event_name) {
     _lock.lock();
 #endif
 
-      if (_token_board->_waiting.is_full()) {
+      if (_token_board->_waiting.full()) {
         loader_cat.error()
           << "Loader::request_load() - Too many pending requests\n";
         return 0;
@@ -161,7 +161,7 @@ request_load(const Filename &filename, const string &event_name) {
       }
 
       tok = new LoaderToken(_next_token++, filename, event_name);
-      _token_board->_waiting.insert(tok);
+      _token_board->_waiting.push_back(tok);
 
 #ifdef HAVE_IPC
       _request_cond->signal();
@@ -171,7 +171,7 @@ request_load(const Filename &filename, const string &event_name) {
   } else {
     // If we're not running asynchronously, process the load request
     // directly now.
-    if (_token_board->_waiting.is_full()) {
+    if (_token_board->_waiting.full()) {
       loader_cat.error()
         << "Loader::request_load() - Too many pending requests\n";
       return 0;
@@ -183,7 +183,7 @@ request_load(const Filename &filename, const string &event_name) {
     }
 
     tok = new LoaderToken(_next_token++, filename, event_name);
-    _token_board->_waiting.insert(tok);
+    _token_board->_waiting.push_back(tok);
     process_request();
   }
 
@@ -264,15 +264,16 @@ process_request() {
   }
 
   // If there is actually a request token - process it
-  while (!_token_board->_waiting.is_empty()) {
-    PT(LoaderToken) tok = _token_board->_waiting.extract();
+  while (!_token_board->_waiting.empty()) {
+    PT(LoaderToken) tok = _token_board->_waiting.front();
+    _token_board->_waiting.pop_front();
     tok->_node = load_file(tok->_path);
     if (tok->_node == NULL) {
       loader_cat.error()
         << "Loader::callback() - couldn't find file: "
         << tok->_path << "\n";
     } else {
-      _token_board->_done.insert(tok);
+      _token_board->_done.push_back(tok);
 
       // Throw a "done" event now.
       if (!tok->_event_name.empty()) {

+ 4 - 0
panda/src/pstatclient/pStatProperties.cxx

@@ -137,6 +137,10 @@ static LevelCollectorProperties level_properties[] = {
   { 1, "Texture memory:In use",            { 0.0, 1.0, 1.0 } },
   { 1, "Texture manager",                  { 1.0, 0.0, 0.0 },  "MB", 12, 1048576 },
   { 1, "Texture manager:Resident",         { 1.0, 1.0, 0.0 } },
+  { 1, "Prepared Geoms",                   { 1.0, 0.0, 0.5 },  "", 500 },
+  { 1, "Prepared Geoms:Active",            { 0.5, 1.0, 0.8 } },
+  { 1, "Prepared GeomNodes",               { 1.0, 0.0, 0.5 },  "", 500 },
+  { 1, "Prepared GeomNodes:Active",        { 0.5, 1.0, 0.8 } },
   { 1, "Vertices",                         { 0.5, 0.2, 0.0 },  "K", 10, 1000 },
   { 1, "Vertices:Other",                   { 0.2, 0.2, 0.2 } },
   { 1, "Vertices:Triangles",               { 0.8, 0.8, 0.8 } },

+ 2 - 2
panda/src/sgattrib/drawBoundsTransition.cxx

@@ -124,9 +124,9 @@ sub_render(NodeRelation *arc, const AllAttributesWrapper &attrib,
       geom.set_coords(verts, G_PER_VERTEX);
       geom.set_num_prims(1);
 
-      gsg->draw_sphere(&geom);
+      gsg->draw_sphere(&geom, NULL);
       gsg->set_state(_inside_attrib, false);
-      gsg->draw_sphere(&geom);
+      gsg->draw_sphere(&geom, NULL);
 
     } else {
       sgattrib_cat.warning()

+ 93 - 5
panda/src/sgraph/geomNode.cxx

@@ -35,6 +35,8 @@ TypeHandle GeomNode::_type_handle;
 ////////////////////////////////////////////////////////////////////
 GeomNode::
 GeomNode(const string &name) : NamedNode(name), _num_geoms(0) {
+  _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+  _prepared_context = (GeomNodeContext *)NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -48,6 +50,8 @@ GeomNode(const GeomNode &copy) :
   _geoms(copy._geoms),
   _num_geoms(0)
 {
+  _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+  _prepared_context = (GeomNodeContext *)NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -57,6 +61,7 @@ GeomNode(const GeomNode &copy) :
 ////////////////////////////////////////////////////////////////////
 void GeomNode::
 operator = (const GeomNode &copy) {
+  unprepare();
   NamedNode::operator = (copy);
   _geoms = copy._geoms;
   _num_geoms = 0;
@@ -69,6 +74,7 @@ operator = (const GeomNode &copy) {
 ////////////////////////////////////////////////////////////////////
 GeomNode::
 ~GeomNode() {
+  unprepare();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -146,9 +152,87 @@ write_verbose(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 void GeomNode::
 draw(GraphicsStateGuardianBase *gsg) {
-  Geoms::const_iterator gi;
-  for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
-    (*gi)->draw(gsg);
+  if (_prepared_gsg == gsg) {
+    gsg->draw_geom_node(this, _prepared_context);
+  } else {
+    Geoms::const_iterator gi;
+    for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
+      (*gi)->draw(gsg);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::prepare
+//       Access: Public
+//  Description: Creates a context for the GeomNode on the particular
+//               GSG, if it does not already exist.  Returns the new
+//               (or old) GeomNodeContext.
+//
+//               If the given GeomNodeContext pointer is non-NULL, it will
+//               be passed to the GSG, which may or may not choose to
+//               extend the existing GeomNodeContext, or create a totally
+//               new one.
+////////////////////////////////////////////////////////////////////
+GeomNodeContext *GeomNode::
+prepare(GraphicsStateGuardianBase *gsg) {
+  if (gsg != _prepared_gsg) {
+    GeomNodeContext *gc = gsg->prepare_geom_node(this);
+    if (gc != (GeomNodeContext *)NULL) {
+      unprepare();
+      _prepared_context = gc;
+      _prepared_gsg = gsg;
+    }
+    return gc;
+  }
+
+  return _prepared_context;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::unprepare
+//       Access: Public
+//  Description: Frees the context allocated on all GSG's for which
+//               the geom has been declared.
+////////////////////////////////////////////////////////////////////
+void GeomNode::
+unprepare() {
+  if (_prepared_gsg != (GraphicsStateGuardianBase *)NULL) {
+    _prepared_gsg->release_geom_node(_prepared_context);
+    _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+    _prepared_context = (GeomNodeContext *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::unprepare
+//       Access: Public
+//  Description: Frees the geom context only on the indicated GSG,
+//               if it exists there.
+////////////////////////////////////////////////////////////////////
+void GeomNode::
+unprepare(GraphicsStateGuardianBase *gsg) {
+  if (_prepared_gsg == gsg) {
+    _prepared_gsg->release_geom_node(_prepared_context);
+    _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+    _prepared_context = (GeomNodeContext *)NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::clear_gsg
+//       Access: Public
+//  Description: Removes the indicated GSG from the Geom's known
+//               GSG's, without actually releasing the geom on that
+//               GSG.  This is intended to be called only from
+//               GSG::release_geom_node(); it should never be called by
+//               user code.
+////////////////////////////////////////////////////////////////////
+void GeomNode::
+clear_gsg(GraphicsStateGuardianBase *gsg) {
+  if (_prepared_gsg == gsg) {
+    _prepared_gsg = (GraphicsStateGuardianBase *)NULL;
+    _prepared_context = (GeomNodeContext *)NULL;
   }
 }
 
@@ -189,10 +273,10 @@ remove_geom(int n) {
 
   } else {
     // Copy-on-write.
-    size_t num_geoms = _geoms.size();
+    int num_geoms = _geoms.size();
     Geoms new_geoms;
     new_geoms.reserve(num_geoms - 1);
-    size_t i;
+    int i;
     for (i = 0; i < n; i++) {
       new_geoms.push_back(_geoms[i]);
     }
@@ -204,6 +288,7 @@ remove_geom(int n) {
     nassertv(_geoms.get_ref_count() == 1);
   }
 
+  unprepare();
   mark_bound_stale();
 }
 
@@ -215,6 +300,7 @@ remove_geom(int n) {
 void GeomNode::
 clear() {
   _geoms.clear();
+  unprepare();
   mark_bound_stale();
 }
 
@@ -239,6 +325,7 @@ add_geom(dDrawable *geom) {
     _geoms.push_back(geom);
   }
 
+  unprepare();
   mark_bound_stale();
   return _geoms.size() - 1;
 }
@@ -268,6 +355,7 @@ add_geoms_from(const GeomNode *other) {
     _geoms.v().insert(_geoms.end(), geoms_begin, geoms_end);
   }
 
+  unprepare();
   mark_bound_stale();
 }
 

+ 12 - 0
panda/src/sgraph/geomNode.h

@@ -30,6 +30,7 @@
 
 class GraphicsStateGuardianBase;
 class AllAttributesWrapper;
+class GeomNodeContext;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : GeomNode
@@ -56,6 +57,11 @@ PUBLISHED:
 public:
   void draw(GraphicsStateGuardianBase *gsg);
 
+  GeomNodeContext *prepare(GraphicsStateGuardianBase *gsg);
+  void unprepare();
+  void unprepare(GraphicsStateGuardianBase *gsg);
+  void clear_gsg(GraphicsStateGuardianBase *gsg);
+
 PUBLISHED:
   int get_num_geoms() const;
   dDrawable *get_geom(int n) const;
@@ -71,6 +77,12 @@ private:
   typedef PTA(PT(dDrawable)) Geoms;
   Geoms _geoms;
 
+  // These are essentially similar to the same fields in Geom.  They
+  // are used only if the GSG supports a node-level Geom context, as
+  // opposed to strictly a Geom-level context.
+  GraphicsStateGuardianBase *_prepared_gsg;
+  GeomNodeContext *_prepared_context;
+
 public:
   static void register_with_read_factory(void);
   virtual void write_datagram(BamWriter* manager, Datagram &me);

+ 1 - 0
panda/src/sgraph/geomTransformer.cxx

@@ -148,6 +148,7 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) {
 
   if (any_changed) {
     node->_geoms = new_geoms;
+    node->unprepare();
     node->mark_bound_stale();
     return true;
   }