فهرست منبع

ibuffers as well as vbuffers

David Rose 21 سال پیش
والد
کامیت
dbed74e410
54فایلهای تغییر یافته به همراه1380 افزوده شده و 407 حذف شده
  1. 67 20
      panda/src/display/graphicsStateGuardian.cxx
  2. 11 5
      panda/src/display/graphicsStateGuardian.h
  3. 2 2
      panda/src/dxgsg8/Sources.pp
  4. 2 2
      panda/src/dxgsg8/config_dxgsg8.cxx
  5. 31 31
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  6. 3 3
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  7. 1 1
      panda/src/dxgsg8/dxVertexBufferContext8.I
  8. 19 17
      panda/src/dxgsg8/dxVertexBufferContext8.cxx
  9. 12 12
      panda/src/dxgsg8/dxVertexBufferContext8.h
  10. 1 1
      panda/src/dxgsg8/dxgsg8_composite1.cxx
  11. 3 3
      panda/src/egg2pg/eggLoader.cxx
  12. 4 4
      panda/src/framework/windowFramework.cxx
  13. 6 3
      panda/src/glstuff/Sources.pp
  14. 187 63
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  15. 9 4
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  16. 5 5
      panda/src/glstuff/glIndexBufferContext_src.I
  17. 2 2
      panda/src/glstuff/glIndexBufferContext_src.cxx
  18. 53 0
      panda/src/glstuff/glIndexBufferContext_src.h
  19. 30 0
      panda/src/glstuff/glVertexBufferContext_src.I
  20. 2 4
      panda/src/glstuff/glVertexBufferContext_src.cxx
  21. 9 9
      panda/src/glstuff/glVertexBufferContext_src.h
  22. 2 1
      panda/src/glstuff/glmisc_src.cxx
  23. 2 1
      panda/src/glstuff/glstuff_src.cxx
  24. 2 1
      panda/src/glstuff/glstuff_src.h
  25. 12 6
      panda/src/gobj/Sources.pp
  26. 4 2
      panda/src/gobj/config_gobj.cxx
  27. 0 1
      panda/src/gobj/gobj_composite1.cxx
  28. 4 2
      panda/src/gobj/gobj_composite2.cxx
  29. 20 20
      panda/src/gobj/indexBufferContext.I
  30. 21 0
      panda/src/gobj/indexBufferContext.cxx
  31. 82 0
      panda/src/gobj/indexBufferContext.h
  32. 259 74
      panda/src/gobj/preparedGraphicsObjects.cxx
  33. 27 11
      panda/src/gobj/preparedGraphicsObjects.h
  34. 46 0
      panda/src/gobj/qpgeomPrimitive.I
  35. 135 1
      panda/src/gobj/qpgeomPrimitive.cxx
  36. 32 2
      panda/src/gobj/qpgeomPrimitive.h
  37. 4 2
      panda/src/gobj/qpgeomTriangles.cxx
  38. 1 1
      panda/src/gobj/qpgeomTriangles.h
  39. 5 3
      panda/src/gobj/qpgeomTrifans.cxx
  40. 1 1
      panda/src/gobj/qpgeomTrifans.h
  41. 5 3
      panda/src/gobj/qpgeomTristrips.cxx
  42. 1 1
      panda/src/gobj/qpgeomTristrips.h
  43. 77 0
      panda/src/gobj/qpgeomUsageHint.h
  44. 5 13
      panda/src/gobj/qpgeomVertexArrayData.I
  45. 16 16
      panda/src/gobj/qpgeomVertexArrayData.cxx
  46. 9 26
      panda/src/gobj/qpgeomVertexArrayData.h
  47. 8 6
      panda/src/gobj/qpgeomVertexData.I
  48. 4 4
      panda/src/gobj/qpgeomVertexData.cxx
  49. 4 3
      panda/src/gobj/qpgeomVertexData.h
  50. 91 0
      panda/src/gobj/vertexBufferContext.I
  51. 21 0
      panda/src/gobj/vertexBufferContext.cxx
  52. 11 11
      panda/src/gobj/vertexBufferContext.h
  53. 8 3
      panda/src/gsgbase/graphicsStateGuardianBase.h
  54. 2 1
      panda/src/pstatclient/pStatProperties.cxx

+ 67 - 20
panda/src/display/graphicsStateGuardian.cxx

@@ -20,7 +20,8 @@
 #include "graphicsStateGuardian.h"
 #include "config_display.h"
 #include "textureContext.h"
-#include "dataContext.h"
+#include "vertexBufferContext.h"
+#include "indexBufferContext.h"
 #include "renderBuffer.h"
 #include "colorAttrib.h"
 #include "colorScaleAttrib.h"
@@ -48,7 +49,8 @@ PStatCollector GraphicsStateGuardian::_active_texusage_pcollector("Texture usage
 PStatCollector GraphicsStateGuardian::_total_geom_pcollector("Prepared Geoms");
 PStatCollector GraphicsStateGuardian::_active_geom_pcollector("Prepared Geoms:Active");
 PStatCollector GraphicsStateGuardian::_total_buffers_pcollector("Vertex buffers");
-PStatCollector GraphicsStateGuardian::_active_buffers_pcollector("Vertex buffers:Active");
+PStatCollector GraphicsStateGuardian::_active_vertex_buffers_pcollector("Vertex buffers:Active vertex");
+PStatCollector GraphicsStateGuardian::_active_index_buffers_pcollector("Vertex buffers:Active index");
 PStatCollector GraphicsStateGuardian::_total_geom_node_pcollector("Prepared GeomNodes");
 PStatCollector GraphicsStateGuardian::_active_geom_node_pcollector("Prepared GeomNodes:Active");
 PStatCollector GraphicsStateGuardian::_total_texmem_pcollector("Texture memory");
@@ -271,25 +273,47 @@ release_geom(GeomContext *) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::prepare_data
+//     Function: GraphicsStateGuardian::prepare_vertex_buffer
 //       Access: Public, Virtual
-//  Description: Prepares the indicated data array for retained-mode
+//  Description: Prepares the indicated buffer for retained-mode
 //               rendering.
 ////////////////////////////////////////////////////////////////////
-DataContext *GraphicsStateGuardian::
-prepare_data(qpGeomVertexArrayData *) {
-  return (DataContext *)NULL;
+VertexBufferContext *GraphicsStateGuardian::
+prepare_vertex_buffer(qpGeomVertexArrayData *) {
+  return (VertexBufferContext *)NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::release_data
+//     Function: GraphicsStateGuardian::release_vertex_buffer
 //       Access: Public, Virtual
 //  Description: Frees the resources previously allocated via a call
-//               to prepare_data(), including deleting the DataContext
-//               itself, if necessary.
+//               to prepare_data(), including deleting the
+//               VertexBufferContext itself, if necessary.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+release_vertex_buffer(VertexBufferContext *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::prepare_index_buffer
+//       Access: Public, Virtual
+//  Description: Prepares the indicated buffer for retained-mode
+//               rendering.
+////////////////////////////////////////////////////////////////////
+IndexBufferContext *GraphicsStateGuardian::
+prepare_index_buffer(qpGeomPrimitive *) {
+  return (IndexBufferContext *)NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::release_index_buffer
+//       Access: Public, Virtual
+//  Description: Frees the resources previously allocated via a call
+//               to prepare_data(), including deleting the
+//               IndexBufferContext itself, if necessary.
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
-release_data(DataContext *) {
+release_index_buffer(IndexBufferContext *) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1443,11 +1467,13 @@ init_frame_pstats() {
   if (PStatClient::is_connected()) {
     _current_textures.clear();
     _current_geoms.clear();
-    _current_datas.clear();
+    _current_vertex_buffers.clear();
+    _current_index_buffers.clear();
     _active_texusage_pcollector.clear_level();
     _active_geom_pcollector.clear_level();
     _active_geom_node_pcollector.clear_level();
-    _active_buffers_pcollector.clear_level();
+    _active_vertex_buffers_pcollector.clear_level();
+    _active_index_buffers_pcollector.clear_level();
     
     // Also clear out our other counters while we're here.
     _vertices_tristrip_pcollector.clear_level();
@@ -1498,21 +1524,42 @@ add_to_geom_record(GeomContext *gc) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::add_to_data_record
+//     Function: GraphicsStateGuardian::add_to_vertex_buffer_record
+//       Access: Protected
+//  Description: Records that the indicated data array has been drawn
+//               this frame.  This function is only used to update the
+//               PStats active_vertex_buffers collector; it gets compiled out
+//               if we aren't using PStats.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+add_to_vertex_buffer_record(VertexBufferContext *vbc) {
+  if (vbc != (VertexBufferContext *)NULL) {
+    int delta = vbc->get_data()->get_data_size_bytes() - vbc->get_data_size_bytes();
+    _total_buffers_pcollector.add_level(delta);
+    if (PStatClient::is_connected()) {
+      if (_current_vertex_buffers.insert(vbc).second) {
+        _active_vertex_buffers_pcollector.add_level(vbc->get_data()->get_data_size_bytes());
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::add_to_index_buffer_record
 //       Access: Protected
 //  Description: Records that the indicated data array has been drawn
 //               this frame.  This function is only used to update the
-//               PStats active_buffers collector; it gets compiled out
+//               PStats active_index_buffers collector; it gets compiled out
 //               if we aren't using PStats.
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
-add_to_data_record(DataContext *dc) {
-  if (dc != (DataContext *)NULL) {
-    int delta = dc->get_data()->get_num_bytes() - dc->get_num_bytes();
+add_to_index_buffer_record(IndexBufferContext *ibc) {
+  if (ibc != (IndexBufferContext *)NULL) {
+    int delta = ibc->get_data()->get_data_size_bytes() - ibc->get_data_size_bytes();
     _total_buffers_pcollector.add_level(delta);
     if (PStatClient::is_connected()) {
-      if (_current_datas.insert(dc).second) {
-        _active_buffers_pcollector.add_level(dc->get_data()->get_num_bytes());
+      if (_current_index_buffers.insert(ibc).second) {
+        _active_index_buffers_pcollector.add_level(ibc->get_data()->get_data_size_bytes());
       }
     }
   }

+ 11 - 5
panda/src/display/graphicsStateGuardian.h

@@ -107,8 +107,11 @@ public:
   virtual GeomContext *prepare_geom(Geom *geom);
   virtual void release_geom(GeomContext *gc);
 
-  virtual DataContext *prepare_data(qpGeomVertexArrayData *data);
-  virtual void release_data(DataContext *gc);
+  virtual VertexBufferContext *prepare_vertex_buffer(qpGeomVertexArrayData *data);
+  virtual void release_vertex_buffer(VertexBufferContext *vbc);
+
+  virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data);
+  virtual void release_index_buffer(IndexBufferContext *ibc);
 
   virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
 
@@ -226,11 +229,13 @@ protected:
   void init_frame_pstats();
   void add_to_texture_record(TextureContext *tc);
   void add_to_geom_record(GeomContext *gc);
-  void add_to_data_record(DataContext *dc);
+  void add_to_vertex_buffer_record(VertexBufferContext *vbc);
+  void add_to_index_buffer_record(IndexBufferContext *ibc);
 
   pset<TextureContext *> _current_textures;
   pset<GeomContext *> _current_geoms;
-  pset<DataContext *> _current_datas;
+  pset<VertexBufferContext *> _current_vertex_buffers;
+  pset<IndexBufferContext *> _current_index_buffers;
 #else
   INLINE void init_frame_pstats() { }
   INLINE void add_to_texture_record(TextureContext *) { }
@@ -314,7 +319,8 @@ public:
   static PStatCollector _total_geom_pcollector;
   static PStatCollector _active_geom_pcollector;
   static PStatCollector _total_buffers_pcollector;
-  static PStatCollector _active_buffers_pcollector;
+  static PStatCollector _active_vertex_buffers_pcollector;
+  static PStatCollector _active_index_buffers_pcollector;
   static PStatCollector _total_geom_node_pcollector;
   static PStatCollector _active_geom_node_pcollector;
   static PStatCollector _total_texmem_pcollector;

+ 2 - 2
panda/src/dxgsg8/Sources.pp

@@ -20,7 +20,7 @@
   // need to install these due to external projects that link directly with libpandadx (bartop)  
   #define INSTALL_HEADERS \
     dxgsg8base.h config_dxgsg8.h dxGraphicsStateGuardian8.I dxGraphicsStateGuardian8.h \
-    dxDataContext8.h \
+    dxVertexBufferContext8.h \
     dxTextureContext8.h \
     dxGeomMunger8.h \
     d3dfont8.h \
@@ -37,7 +37,7 @@
     
   #define INCLUDED_SOURCES \
     config_dxgsg8.cxx \
-    dxDataContext8.cxx \
+    dxVertexBufferContext8.cxx \
     dxTextureContext8.cxx \
     dxGeomMunger8.cxx \
     d3dfont8.cxx \

+ 2 - 2
panda/src/dxgsg8/config_dxgsg8.cxx

@@ -19,7 +19,7 @@
 #include "config_dxgsg8.h"
 #include "dxGraphicsStateGuardian8.h"
 #include "dxTextureContext8.h"
-#include "dxDataContext8.h"
+#include "dxVertexBufferContext8.h"
 #include "dxGeomMunger8.h"
 #include "graphicsPipeSelection.h"
 #include "wdxGraphicsWindow8.h"
@@ -145,7 +145,7 @@ init_libdxgsg8() {
 
   DXGraphicsStateGuardian8::init_type();
   DXTextureContext8::init_type();
-  DXDataContext8::init_type();
+  DXVertexBufferContext8::init_type();
   DXGeomMunger8::init_type();
 
   wdxGraphicsPipe8::init_type();

+ 31 - 31
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -56,7 +56,7 @@
 #include "qpgeomTrifans.h"
 #include "dxGeomMunger8.h"
 #include "config_gobj.h"
-#include "dxDataContext8.h"
+#include "dxVertexBufferContext8.h"
 
 #ifdef DO_PSTATS
 #include "pStatTimer.h"
@@ -2620,8 +2620,8 @@ begin_draw_primitives(const qpGeomVertexData *vertex_data) {
   // the first array.
   const qpGeomVertexArrayData *data = _vertex_data->get_array(0);
 
-  DataContext *dc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this);
-  nassertr(dc != (DataContext *)NULL, false);
+  VertexBufferContext *dc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this);
+  nassertr(dc != (VertexBufferContext *)NULL, false);
   apply_data(dc);
 
   return true;
@@ -2903,79 +2903,79 @@ release_texture(TextureContext *tc) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::prepare_data
+//     Function: DXGraphicsStateGuardian8::prepare_vertex_buffer
 //       Access: Public, Virtual
 //  Description: Creates a new retained-mode representation of the
 //               given data, and returns a newly-allocated
-//               DataContext pointer to reference it.  It is the
+//               VertexBufferContext pointer to reference it.  It is the
 //               responsibility of the calling function to later
-//               call release_data() with this same pointer (which
+//               call release_vertex_buffer() with this same pointer (which
 //               will also delete the pointer).
 //
 //               This function should not be called directly to
 //               prepare a data.  Instead, call Data::prepare().
 ////////////////////////////////////////////////////////////////////
-DataContext *DXGraphicsStateGuardian8::
-prepare_data(qpGeomVertexArrayData *data) {
+VertexBufferContext *DXGraphicsStateGuardian8::
+prepare_vertex_buffer(qpGeomVertexArrayData *data) {
   if (dxgsg8_cat.is_debug()) {
     dxgsg8_cat.debug()
-      << "prepare_data(" << (void *)data << ")\n";
+      << "prepare_vertex_buffer(" << (void *)data << ")\n";
   }
 
-  DXDataContext8 *ddc = new DXDataContext8(data);
+  DXVertexBufferContext8 *dvbc = new DXVertexBufferContext8(data);
 
   if (vertex_buffers) {
-    ddc->create_vbuffer(*_pScrn);
-    ddc->mark_loaded();
+    dvbc->create_vbuffer(*_pScrn);
+    dvbc->mark_loaded();
   }
 
-  return ddc;
+  return dvbc;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::apply_data
+//     Function: DXGraphicsStateGuardian8::apply_vertex_buffer
 //       Access: Public
 //  Description: Makes the data the currently available data for
 //               rendering.
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
-apply_data(DataContext *dc) {
-  DXDataContext8 *ddc = DCAST(DXDataContext8, dc);
+apply_vertex_buffer(VertexBufferContext *vbc) {
+  DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
 
-  if (ddc->_vbuffer != NULL) {
-    add_to_data_record(ddc);
+  if (dvbc->_vbuffer != NULL) {
+    add_to_vertex_buffer_record(dvbc);
   
-    if (ddc->was_modified()) {
+    if (dvbc->was_modified()) {
       if (dxgsg8_cat.is_debug()) {
         dxgsg8_cat.debug()
-          << "apply_data(" << (void *)dc->get_data() << ")\n";
+          << "apply_vertex_buffer(" << (void *)vbc->get_data() << ")\n";
       }
-      if (ddc->changed_size()) {
+      if (dvbc->changed_size()) {
         // Here we have to destroy the old vertex buffer and create a
         // new one.
-        ddc->create_vbuffer(*_pScrn);
+        dvbc->create_vbuffer(*_pScrn);
 
       } else {
         // Here we just copy the new data to the vertex buffer.
-        ddc->upload_data();
+        dvbc->upload_data();
       }
       
-      ddc->mark_loaded();
+      dvbc->mark_loaded();
     }
 
     _pD3DDevice->SetStreamSource
-      (0, ddc->_vbuffer, ddc->get_data()->get_array_format()->get_stride());
+      (0, dvbc->_vbuffer, dvbc->get_data()->get_array_format()->get_stride());
     _vbuffer_active = true;
 
   } else {
     _vbuffer_active = false;
   }
 
-  set_vertex_format(ddc->_fvf);
+  set_vertex_format(dvbc->_fvf);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::release_data
+//     Function: DXGraphicsStateGuardian8::release_vertex_buffer
 //       Access: Public, Virtual
 //  Description: Frees the GL resources previously allocated for the
 //               data.  This function should never be called
@@ -2983,14 +2983,14 @@ apply_data(DataContext *dc) {
 //               let the Data destruct).
 ////////////////////////////////////////////////////////////////////
 void DXGraphicsStateGuardian8::
-release_data(DataContext *dc) {
+release_vertex_buffer(VertexBufferContext *vbc) {
   if (dxgsg8_cat.is_debug()) {
     dxgsg8_cat.debug()
-      << "release_data(" << (void *)dc->get_data() << ")\n";
+      << "release_vertex_buffer(" << (void *)vbc->get_data() << ")\n";
   }
 
-  DXDataContext8 *ddc = DCAST(DXDataContext8, dc);
-  delete ddc;
+  DXVertexBufferContext8 *dvbc = DCAST(DXVertexBufferContext8, vbc);
+  delete dvbc;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 3
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -99,9 +99,9 @@ public:
   virtual void apply_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
-  virtual DataContext *prepare_data(qpGeomVertexArrayData *data);
-  void apply_data(DataContext *dc);
-  virtual void release_data(DataContext *dc);
+  virtual VertexBufferContext *prepare_vertex_buffer(qpGeomVertexArrayData *data);
+  void apply_vertex_buffer(VertexBufferContext *vbc);
+  virtual void release_vertex_buffer(VertexBufferContext *vbc);
 
   virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
 

+ 1 - 1
panda/src/dxgsg8/dxDataContext8.I → panda/src/dxgsg8/dxVertexBufferContext8.I

@@ -1,4 +1,4 @@
-// Filename: dxDataContext8.I
+// Filename: dxVertexBufferContext8.I
 // Created by:  drose (18Mar05)
 //
 ////////////////////////////////////////////////////////////////////

+ 19 - 17
panda/src/dxgsg8/dxDataContext8.cxx → panda/src/dxgsg8/dxVertexBufferContext8.cxx

@@ -1,4 +1,4 @@
-// Filename: dxDataContext8.cxx
+// Filename: dxVertexBufferContext8.cxx
 // Created by:  drose (18Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,23 +16,23 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "dxDataContext8.h"
+#include "dxVertexBufferContext8.h"
 #include "qpgeomVertexArrayData.h"
 #include "qpgeomVertexArrayFormat.h"
 #include "internalName.h"
 #include "config_dxgsg8.h"
 #include <d3dx8.h>
 
-TypeHandle DXDataContext8::_type_handle;
+TypeHandle DXVertexBufferContext8::_type_handle;
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXDataContext8::Constructor
+//     Function: DXVertexBufferContext8::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-DXDataContext8::
-DXDataContext8(qpGeomVertexArrayData *data) :
-  DataContext(data),
+DXVertexBufferContext8::
+DXVertexBufferContext8(qpGeomVertexArrayData *data) :
+  VertexBufferContext(data),
   _vbuffer(NULL)
 {
   // Now fill in the FVF code.
@@ -88,12 +88,12 @@ DXDataContext8(qpGeomVertexArrayData *data) :
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXDataContext8::Destructor
+//     Function: DXVertexBufferContext8::Destructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-DXDataContext8::
-~DXDataContext8() {
+DXVertexBufferContext8::
+~DXVertexBufferContext8() {
   if (_vbuffer != NULL) {
     RELEASE(_vbuffer, dxgsg8, "vertex buffer", RELEASE_ONCE);
     _vbuffer = NULL;
@@ -101,11 +101,11 @@ DXDataContext8::
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXDataContext8::create_vbuffer
+//     Function: DXVertexBufferContext8::create_vbuffer
 //       Access: Public
 //  Description: Creates a new vertex buffer and uploads data to it.
 ////////////////////////////////////////////////////////////////////
-void DXDataContext8::
+void DXVertexBufferContext8::
 create_vbuffer(DXScreenData &scrn) {
   if (_vbuffer != NULL) {
     RELEASE(_vbuffer, dxgsg8, "vertex buffer", RELEASE_ONCE);
@@ -113,7 +113,7 @@ create_vbuffer(DXScreenData &scrn) {
   }
 
   HRESULT hr = scrn.pD3DDevice->CreateVertexBuffer
-    (get_data()->get_num_bytes(), D3DUSAGE_WRITEONLY,
+    (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY,
      _fvf, D3DPOOL_MANAGED, &_vbuffer);
   if (FAILED(hr)) {
     dxgsg8_cat.warning()
@@ -126,24 +126,26 @@ create_vbuffer(DXScreenData &scrn) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DXDataContext8::upload_data
+//     Function: DXVertexBufferContext8::upload_data
 //       Access: Public
 //  Description: Copies the latest data from the client store to
 //               DirectX.
 ////////////////////////////////////////////////////////////////////
-void DXDataContext8::
+void DXVertexBufferContext8::
 upload_data() {
   nassertv(_vbuffer != NULL);
 
+  int data_size = get_data()->get_data_size_bytes();
+
   BYTE *local_pointer;
-  HRESULT hr = _vbuffer->Lock(0, 0, &local_pointer, 0);
+  HRESULT hr = _vbuffer->Lock(0, data_size, &local_pointer, 0);
   if (FAILED(hr)) {
     dxgsg8_cat.error()
       << "VertexBuffer::Lock failed" << D3DERRORSTRING(hr);
     return;
   }
 
-  memcpy(local_pointer, get_data()->get_data(), get_data()->get_num_bytes());
+  memcpy(local_pointer, get_data()->get_data(), data_size);
 
   _vbuffer->Unlock();
 }

+ 12 - 12
panda/src/dxgsg8/dxDataContext8.h → panda/src/dxgsg8/dxVertexBufferContext8.h

@@ -1,4 +1,4 @@
-// Filename: dxDataContext8.h
+// Filename: dxVertexBufferContext8.h
 // Created by:  drose (18Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,22 +16,22 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef DXDATACONTEXT8_H
-#define DXDATACONTEXT8_H
+#ifndef DXVERTEXBUFFERCONTEXT8_H
+#define DXVERTEXBUFFERCONTEXT8_H
 
 #include "pandabase.h"
 #include "dxgsg8base.h"
-#include "dataContext.h"
+#include "vertexBufferContext.h"
 
 ////////////////////////////////////////////////////////////////////
-//       Class : DXDataContext8
+//       Class : DXVertexBufferContext8
 // Description : Caches a GeomVertexArrayData in the DirectX device as
 //               a vertex buffer.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDADX DXDataContext8 : public DataContext {
+class EXPCL_PANDADX DXVertexBufferContext8 : public VertexBufferContext {
 public:
-  DXDataContext8(qpGeomVertexArrayData *data);
-  virtual ~DXDataContext8();
+  DXVertexBufferContext8(qpGeomVertexArrayData *data);
+  virtual ~DXVertexBufferContext8();
 
   void create_vbuffer(DXScreenData &scrn);
   void upload_data();
@@ -44,9 +44,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    DataContext::init_type();
-    register_type(_type_handle, "DXDataContext8",
-                  DataContext::get_class_type());
+    VertexBufferContext::init_type();
+    register_type(_type_handle, "DXVertexBufferContext8",
+                  VertexBufferContext::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();
@@ -57,7 +57,7 @@ private:
   static TypeHandle _type_handle;
 };
 
-#include "dxDataContext8.I"
+#include "dxVertexBufferContext8.I"
 
 #endif
 

+ 1 - 1
panda/src/dxgsg8/dxgsg8_composite1.cxx

@@ -1,7 +1,7 @@
 #include "dxgsg8base.h"
 #include "config_dxgsg8.cxx"
 #include "dxTextureContext8.cxx"
-#include "dxDataContext8.cxx"
+#include "dxVertexBufferContext8.cxx"
 #include "dxGeomMunger8.cxx"
 #include "d3dfont8.cxx"
 #include "wdxGraphicsPipe8.cxx"

+ 3 - 3
panda/src/egg2pg/eggLoader.cxx

@@ -1926,7 +1926,7 @@ make_vertex_data(EggVertexPool *vertex_pool, const LMatrix4d &transform) {
 
   // Now create a new GeomVertexData using the indicated format.
   PT(qpGeomVertexData) vertex_data = 
-    new qpGeomVertexData(format, qpGeomVertexArrayData::UH_static);
+    new qpGeomVertexData(format, qpGeomUsageHint::UH_static);
 
   // And fill the data from the vertex pool.
   EggVertexPool::const_iterator vi;
@@ -1979,10 +1979,10 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
   PT(qpGeomPrimitive) primitive;
   if (egg_prim->is_of_type(EggPolygon::get_class_type())) {
     if (egg_prim->size() == 3) {
-      primitive = new qpGeomTriangles;
+      primitive = new qpGeomTriangles(qpGeomUsageHint::UH_static);
     }
   } else if (egg_prim->is_of_type(EggTriangleStrip::get_class_type())) {
-    primitive = new qpGeomTristrips;
+    primitive = new qpGeomTristrips(qpGeomUsageHint::UH_static);
   }
 
   if (primitive == (qpGeomPrimitive *)NULL) {

+ 4 - 4
panda/src/framework/windowFramework.cxx

@@ -634,7 +634,7 @@ load_default_model(const NodePath &parent) {
     // New, experimental Geom code.
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
       (qpGeomVertexFormat::get_v3n3cpt2(),
-       qpGeomVertexArrayData::UH_static);
+       qpGeomUsageHint::UH_static);
     qpGeomVertexIterator vertex(vdata, InternalName::get_vertex());
     qpGeomVertexIterator normal(vdata, InternalName::get_normal());
     qpGeomVertexIterator color(vdata, InternalName::get_color());
@@ -656,7 +656,7 @@ load_default_model(const NodePath &parent) {
     texcoord.set_data2(1.0, 0.0);
     texcoord.set_data2(0.0, 1.0);
     
-    PT(qpGeomTriangles) tri = new qpGeomTriangles;
+    PT(qpGeomTriangles) tri = new qpGeomTriangles(qpGeomUsageHint::UH_static);
     tri->add_consecutive_vertices(0, 3);
     tri->close_primitive();
     
@@ -1061,7 +1061,7 @@ load_image_as_model(const Filename &filename) {
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
       (qpGeomVertexFormat::get_v3t2(),
-       qpGeomVertexArrayData::UH_static);
+       qpGeomUsageHint::UH_static);
     qpGeomVertexIterator vertex(vdata, InternalName::get_vertex());
     qpGeomVertexIterator texcoord(vdata, InternalName::get_texcoord());
 
@@ -1075,7 +1075,7 @@ load_image_as_model(const Filename &filename) {
     texcoord.set_data2(1.0f, 1.0f);
     texcoord.set_data2(1.0f, 0.0f);
     
-    PT(qpGeomTristrips) strip = new qpGeomTristrips;
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
     strip->add_consecutive_vertices(0, 4);
     strip->close_primitive();
     

+ 6 - 3
panda/src/glstuff/Sources.pp

@@ -19,9 +19,12 @@
      glstuff_src.cxx \
      glstuff_src.h \
      glstuff_undef_src.h \
-     glDataContext_src.cxx \
-     glDataContext_src.I \
-     glDataContext_src.h \
+     glVertexBufferContext_src.cxx \
+     glVertexBufferContext_src.I \
+     glVertexBufferContext_src.h \
+     glIndexBufferContext_src.cxx \
+     glIndexBufferContext_src.I \
+     glIndexBufferContext_src.h \
      glGeomContext_src.cxx \
      glGeomContext_src.I \
      glGeomContext_src.h \

+ 187 - 63
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -596,6 +596,18 @@ reset() {
     GLCAT.debug()
       << "max_elements_vertices = " << max_elements_vertices
       << ", max_elements_indices = " << max_elements_indices << "\n";
+    if (_supports_buffers) {
+      if (vertex_buffers) {
+        GLCAT.debug()
+          << "vertex buffer objects are supported.\n";
+      } else {
+        GLCAT.debug()
+          << "vertex buffer objects are supported (but not enabled).\n";
+      }
+    } else {
+      GLCAT.debug()
+        << "vertex buffer objects are NOT supported.\n";
+    }
   }
 
   report_my_gl_errors();
@@ -2107,11 +2119,14 @@ void CLP(GraphicsStateGuardian)::
 draw_triangles(const qpGeomTriangles *primitive) {
   setup_antialias_polygon();
 
+  _vertices_tri_pcollector.add_level(primitive->get_num_vertices());
+  const unsigned short *client_pointer = setup_primitive(primitive);
+ 
   _glDrawRangeElements(GL_TRIANGLES, 
                        primitive->get_min_vertex(),
                        primitive->get_max_vertex(),
                        primitive->get_num_vertices(),
-                       GL_UNSIGNED_SHORT, primitive->get_flat_last_vertices());
+                       GL_UNSIGNED_SHORT, client_pointer);
 
   report_my_gl_errors();
 }
@@ -2125,7 +2140,9 @@ void CLP(GraphicsStateGuardian)::
 draw_tristrips(const qpGeomTristrips *primitive) {
   setup_antialias_polygon();
 
-  CPTA_ushort vertices = primitive->get_flat_last_vertices();
+  _vertices_tristrip_pcollector.add_level(primitive->get_num_vertices());
+  const unsigned short *client_pointer = setup_primitive(primitive);
+
   CPTA_int ends = primitive->get_ends();
   CPTA_ushort mins = primitive->get_mins();
   CPTA_ushort maxs = primitive->get_maxs();
@@ -2135,7 +2152,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
   for (size_t i = 0; i < ends.size(); i++) {
     _glDrawRangeElements(GL_TRIANGLE_STRIP, 
                          mins[i], maxs[i], ends[i] - start,
-                         GL_UNSIGNED_SHORT, vertices + start);
+                         GL_UNSIGNED_SHORT, client_pointer + start);
     start = ends[i];
   }
 
@@ -2334,83 +2351,74 @@ release_geom(GeomContext *gc) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::prepare_data
+//     Function: CLP(GraphicsStateGuardian)::prepare_vertex_buffer
 //       Access: Public, Virtual
 //  Description: Creates a new retained-mode representation of the
 //               given data, and returns a newly-allocated
-//               DataContext pointer to reference it.  It is the
+//               VertexBufferContext pointer to reference it.  It is the
 //               responsibility of the calling function to later
-//               call release_data() with this same pointer (which
+//               call release_vertex_buffer() with this same pointer (which
 //               will also delete the pointer).
 //
 //               This function should not be called directly to
 //               prepare a data.  Instead, call Data::prepare().
 ////////////////////////////////////////////////////////////////////
-DataContext *CLP(GraphicsStateGuardian)::
-prepare_data(qpGeomVertexArrayData *data) {
+VertexBufferContext *CLP(GraphicsStateGuardian)::
+prepare_vertex_buffer(qpGeomVertexArrayData *data) {
   if (GLCAT.is_debug()) {
     GLCAT.debug()
-      << "prepare_data(" << (void *)data << ")\n";
+      << "prepare_vertex_buffer(" << (void *)data << ")\n";
   }
 
   if (_supports_buffers) {
-    CLP(DataContext) *gdc = new CLP(DataContext)(data);
-    _glGenBuffers(1, &gdc->_index);
-
-    /*
-    _glBindBuffer(GL_ARRAY_BUFFER, gdc->_index);
-    _glBufferData(GL_ARRAY_BUFFER, gdc->get_data()->get_num_bytes(),
-                  gdc->get_data()->get_data(), 
-                  get_usage(gdc->get_data()->get_usage_hint()));
-    add_to_data_record(gdc);
-    gdc->mark_loaded();
-    */
+    CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(data);
+    _glGenBuffers(1, &gvbc->_index);
     
     report_my_gl_errors();
-    return gdc;
+    return gvbc;
   }
 
   return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::apply_data
+//     Function: CLP(GraphicsStateGuardian)::apply_vertex_buffer
 //       Access: Public
 //  Description: Makes the data the currently available data for
 //               rendering.
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
-apply_data(DataContext *dc) {
+apply_vertex_buffer(VertexBufferContext *vbc) {
   nassertv(_supports_buffers);
 
-  CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc);
+  CLP(VertexBufferContext) *gvbc = DCAST(CLP(VertexBufferContext), vbc);
 
-  _glBindBuffer(GL_ARRAY_BUFFER, gdc->_index);
+  _glBindBuffer(GL_ARRAY_BUFFER, gvbc->_index);
   
-  add_to_data_record(gdc);
-  if (gdc->was_modified()) {
+  add_to_vertex_buffer_record(gvbc);
+  if (gvbc->was_modified()) {
     if (GLCAT.is_debug()) {
       GLCAT.debug()
-        << "apply_data(" << (void *)dc->get_data() << ")\n";
+        << "apply_vertex_buffer(" << (void *)vbc->get_data() << ")\n";
     }
-    if (gdc->changed_size()) {
-      _glBufferData(GL_ARRAY_BUFFER, gdc->get_data()->get_num_bytes(),
-                    gdc->get_data()->get_data(), 
-                    get_usage(gdc->get_data()->get_usage_hint()));
+    if (gvbc->changed_size()) {
+      _glBufferData(GL_ARRAY_BUFFER, gvbc->get_data()->get_data_size_bytes(),
+                    gvbc->get_data()->get_data(), 
+                    get_usage(gvbc->get_data()->get_usage_hint()));
 
     } else {
-      _glBufferSubData(GL_ARRAY_BUFFER, 0, gdc->get_num_bytes(),
-                       gdc->get_data()->get_data());
+      _glBufferSubData(GL_ARRAY_BUFFER, 0, gvbc->get_data_size_bytes(),
+                       gvbc->get_data()->get_data());
     }
 
-    gdc->mark_loaded();
+    gvbc->mark_loaded();
   }
 
   report_my_gl_errors();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(GraphicsStateGuardian)::release_data
+//     Function: CLP(GraphicsStateGuardian)::release_vertex_buffer
 //       Access: Public, Virtual
 //  Description: Frees the GL resources previously allocated for the
 //               data.  This function should never be called
@@ -2418,22 +2426,22 @@ apply_data(DataContext *dc) {
 //               let the Data destruct).
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
-release_data(DataContext *dc) {
+release_vertex_buffer(VertexBufferContext *vbc) {
   if (GLCAT.is_debug()) {
     GLCAT.debug()
-      << "release_data(" << (void *)dc->get_data() << ")\n";
+      << "release_vertex_buffer(" << (void *)vbc->get_data() << ")\n";
   }
 
   nassertv(_supports_buffers);
   
-  CLP(DataContext) *gdc = DCAST(CLP(DataContext), dc);
+  CLP(VertexBufferContext) *gvbc = DCAST(CLP(VertexBufferContext), vbc);
 
-  _glDeleteBuffers(1, &gdc->_index);
+  _glDeleteBuffers(1, &gvbc->_index);
   report_my_gl_errors();
 
-  gdc->_index = 0;
+  gvbc->_index = 0;
 
-  delete gdc;
+  delete gvbc;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -2457,7 +2465,7 @@ setup_array_data(const qpGeomVertexArrayData *data) {
     return data->get_data();
   }
   if (!vertex_buffers ||
-      data->get_usage_hint() == qpGeomVertexArrayData::UH_client) {
+      data->get_usage_hint() == qpGeomUsageHint::UH_client) {
     // The array specifies client rendering only, or buffer objects
     // are configured off.
     _glBindBuffer(GL_ARRAY_BUFFER, 0);
@@ -2465,28 +2473,144 @@ setup_array_data(const qpGeomVertexArrayData *data) {
   }
 
   // Prepare the buffer object and bind it.
-  DataContext *dc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this);
-  nassertr(dc != (DataContext *)NULL, data->get_data());
-  apply_data(dc);
+  VertexBufferContext *vbc = ((qpGeomVertexArrayData *)data)->prepare_now(get_prepared_objects(), this);
+  nassertr(vbc != (VertexBufferContext *)NULL, data->get_data());
+  apply_vertex_buffer(vbc);
 
   // NULL is the OpenGL convention for the first byte of the buffer.
   return NULL;
 }
 
-#if 0
-static int logs[] = { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048,
-                      4096, 0 };
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::prepare_index_buffer
+//       Access: Public, Virtual
+//  Description: Creates a new retained-mode representation of the
+//               given data, and returns a newly-allocated
+//               IndexBufferContext pointer to reference it.  It is the
+//               responsibility of the calling function to later
+//               call release_index_buffer() with this same pointer (which
+//               will also delete the pointer).
+//
+//               This function should not be called directly to
+//               prepare a data.  Instead, call Data::prepare().
+////////////////////////////////////////////////////////////////////
+IndexBufferContext *CLP(GraphicsStateGuardian)::
+prepare_index_buffer(qpGeomPrimitive *data) {
+  if (GLCAT.is_debug()) {
+    GLCAT.debug()
+      << "prepare_index_buffer(" << (void *)data << ")\n";
+  }
+
+  if (_supports_buffers) {
+    CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(data);
+    _glGenBuffers(1, &gibc->_index);
+    
+    report_my_gl_errors();
+    return gibc;
+  }
 
-// This function returns the smallest power of two greater than or
-// equal to x.
-static int binary_log_cap(const int x) {
-  int i = 0;
-  for (; (x > logs[i]) && (logs[i] != 0); ++i);
-  if (logs[i] == 0)
-    return 4096;
-  return logs[i];
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::apply_index_buffer
+//       Access: Public
+//  Description: Makes the data the currently available data for
+//               rendering.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+apply_index_buffer(IndexBufferContext *ibc) {
+  nassertv(_supports_buffers);
+
+  CLP(IndexBufferContext) *gibc = DCAST(CLP(IndexBufferContext), ibc);
+
+  _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gibc->_index);
+  
+  add_to_index_buffer_record(gibc);
+  if (gibc->was_modified()) {
+    if (GLCAT.is_debug()) {
+      GLCAT.debug()
+        << "apply_index_buffer(" << (void *)ibc->get_data() << ")\n";
+    }
+    if (gibc->changed_size()) {
+      _glBufferData(GL_ELEMENT_ARRAY_BUFFER, gibc->get_data()->get_data_size_bytes(),
+                    gibc->get_data()->get_vertices(), 
+                    get_usage(gibc->get_data()->get_usage_hint()));
+
+    } else {
+      _glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, gibc->get_data_size_bytes(),
+                       gibc->get_data()->get_vertices());
+    }
+
+    gibc->mark_loaded();
+  }
+
+  report_my_gl_errors();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::release_index_buffer
+//       Access: Public, Virtual
+//  Description: Frees the GL resources previously allocated for the
+//               data.  This function should never be called
+//               directly; instead, call Data::release() (or simply
+//               let the Data destruct).
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+release_index_buffer(IndexBufferContext *ibc) {
+  if (GLCAT.is_debug()) {
+    GLCAT.debug()
+      << "release_index_buffer(" << (void *)ibc->get_data() << ")\n";
+  }
+
+  nassertv(_supports_buffers);
+  
+  CLP(IndexBufferContext) *gibc = DCAST(CLP(IndexBufferContext), ibc);
+
+  _glDeleteBuffers(1, &gibc->_index);
+  report_my_gl_errors();
+
+  gibc->_index = 0;
+
+  delete gibc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::setup_primitive
+//       Access: Public
+//  Description: Internal function to bind a buffer object for the
+//               indicated primitive's index list, if appropriate, or
+//               to unbind a buffer object if it should be rendered
+//               from client memory.
+//
+//               If the buffer object is bound, this function returns
+//               NULL (reprsenting the start of the buffer object in
+//               server memory); if the buffer object is not bound,
+//               this function returns the pointer to the data array
+//               in client memory, that is, the data array passed in.
+////////////////////////////////////////////////////////////////////
+const unsigned short *CLP(GraphicsStateGuardian)::
+setup_primitive(const qpGeomPrimitive *data) {
+  if (!_supports_buffers) {
+    // No support for buffer objects; always render from client.
+    return data->get_vertices();
+  }
+  if (!vertex_buffers ||
+      data->get_usage_hint() == qpGeomUsageHint::UH_client) {
+    // The array specifies client rendering only, or buffer objects
+    // are configured off.
+    _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+    return data->get_vertices();
+  }
+
+  // Prepare the buffer object and bind it.
+  IndexBufferContext *ibc = ((qpGeomPrimitive *)data)->prepare_now(get_prepared_objects(), this);
+  nassertr(ibc != (IndexBufferContext *)NULL, data->get_vertices());
+  apply_index_buffer(ibc);
+
+  // NULL is the OpenGL convention for the first byte of the buffer.
+  return NULL;
 }
-#endif
 
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_geom_munger
@@ -4598,18 +4722,18 @@ get_blend_func(ColorBlendAttrib::Operand operand) {
 //  Description: Maps from UsageHint to the GL symbol.
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
-get_usage(qpGeomVertexArrayData::UsageHint usage_hint) {
+get_usage(qpGeomUsageHint::UsageHint usage_hint) {
   switch (usage_hint) {
-  case qpGeomVertexArrayData::UH_stream:
+  case qpGeomUsageHint::UH_stream:
     return GL_STREAM_DRAW;
 
-  case qpGeomVertexArrayData::UH_static:
+  case qpGeomUsageHint::UH_static:
     return GL_STATIC_DRAW;
 
-  case qpGeomVertexArrayData::UH_dynamic:
+  case qpGeomUsageHint::UH_dynamic:
     return GL_DYNAMIC_DRAW;
 
-  case qpGeomVertexArrayData::UH_client:
+  case qpGeomUsageHint::UH_client:
     break;
   }
 

+ 9 - 4
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -104,11 +104,16 @@ public:
   virtual GeomContext *prepare_geom(Geom *geom);
   virtual void release_geom(GeomContext *gc);
 
-  virtual DataContext *prepare_data(qpGeomVertexArrayData *data);
-  void apply_data(DataContext *dc);
-  virtual void release_data(DataContext *dc);
+  virtual VertexBufferContext *prepare_vertex_buffer(qpGeomVertexArrayData *data);
+  void apply_vertex_buffer(VertexBufferContext *vbc);
+  virtual void release_vertex_buffer(VertexBufferContext *vbc);
   const unsigned char *setup_array_data(const qpGeomVertexArrayData *data);
 
+  virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data);
+  void apply_index_buffer(IndexBufferContext *ibc);
+  virtual void release_index_buffer(IndexBufferContext *ibc);
+  const unsigned short *setup_primitive(const qpGeomPrimitive *data);
+
   virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
 
   virtual void framebuffer_copy_to_texture
@@ -242,7 +247,7 @@ protected:
   static GLenum get_fog_mode_type(Fog::Mode m);
   static GLenum get_blend_equation_type(ColorBlendAttrib::Mode mode);
   static GLenum get_blend_func(ColorBlendAttrib::Operand operand);
-  static GLenum get_usage(qpGeomVertexArrayData::UsageHint usage_hint);
+  static GLenum get_usage(qpGeomUsageHint::UsageHint usage_hint);
 
   static CPT(RenderState) get_untextured_state();
   static CPT(RenderState) get_smooth_state();

+ 5 - 5
panda/src/glstuff/glDataContext_src.I → panda/src/glstuff/glIndexBufferContext_src.I

@@ -1,4 +1,4 @@
-// Filename: glDataContext_src.I
+// Filename: glIndexBufferContext_src.I
 // Created by:  drose (17Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -18,13 +18,13 @@
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: CLP(DataContext)::Constructor
+//     Function: CLP(IndexBufferContext)::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE CLP(DataContext)::
-CLP(DataContext)(qpGeomVertexArrayData *data) :
-  DataContext(data)
+INLINE CLP(IndexBufferContext)::
+CLP(IndexBufferContext)(qpGeomPrimitive *data) :
+  IndexBufferContext(data)
 {
   _index = 0;
 }

+ 2 - 2
panda/src/glstuff/glDataContext_src.cxx → panda/src/glstuff/glIndexBufferContext_src.cxx

@@ -1,4 +1,4 @@
-// Filename: glDataContext_src.cxx
+// Filename: glIndexBufferContext_src.cxx
 // Created by:  drose (17Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,4 +16,4 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-TypeHandle CLP(DataContext)::_type_handle;
+TypeHandle CLP(IndexBufferContext)::_type_handle;

+ 53 - 0
panda/src/glstuff/glIndexBufferContext_src.h

@@ -0,0 +1,53 @@
+// Filename: glIndexBufferContext_src.h
+// Created by:  drose (17Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+#include "indexBufferContext.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : GLIndexBufferContext
+// Description : Caches a GeomPrimitive on the GL as a buffer
+//               object.
+////////////////////////////////////////////////////////////////////
+class EXPCL_GL CLP(IndexBufferContext) : public IndexBufferContext {
+public:
+  INLINE CLP(IndexBufferContext)(qpGeomPrimitive *data);
+
+  // This is the GL "name" of the data object.
+  GLuint _index;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    IndexBufferContext::init_type();
+    register_type(_type_handle, CLASSPREFIX_QUOTED "IndexBufferContext",
+                  IndexBufferContext::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 "glIndexBufferContext_src.I"
+

+ 30 - 0
panda/src/glstuff/glVertexBufferContext_src.I

@@ -0,0 +1,30 @@
+// Filename: glVertexBufferContext_src.I
+// Created by:  drose (17Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(VertexBufferContext)::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE CLP(VertexBufferContext)::
+CLP(VertexBufferContext)(qpGeomVertexArrayData *data) :
+  VertexBufferContext(data)
+{
+  _index = 0;
+}

+ 2 - 4
panda/src/gobj/dataContext.cxx → panda/src/glstuff/glVertexBufferContext_src.cxx

@@ -1,4 +1,4 @@
-// Filename: dataContext.cxx
+// Filename: glVertexBufferContext_src.cxx
 // Created by:  drose (17Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,6 +16,4 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "dataContext.h"
-
-TypeHandle DataContext::_type_handle;
+TypeHandle CLP(VertexBufferContext)::_type_handle;

+ 9 - 9
panda/src/glstuff/glDataContext_src.h → panda/src/glstuff/glVertexBufferContext_src.h

@@ -1,4 +1,4 @@
-// Filename: glDataContext_src.h
+// Filename: glVertexBufferContext_src.h
 // Created by:  drose (17Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -17,16 +17,16 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "pandabase.h"
-#include "dataContext.h"
+#include "vertexBufferContext.h"
 
 ////////////////////////////////////////////////////////////////////
-//       Class : GLDataContext
+//       Class : GLVertexBufferContext
 // Description : Caches a GeomVertexArrayData on the GL as a buffer
 //               object.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_GL CLP(DataContext) : public DataContext {
+class EXPCL_GL CLP(VertexBufferContext) : public VertexBufferContext {
 public:
-  INLINE CLP(DataContext)(qpGeomVertexArrayData *data);
+  INLINE CLP(VertexBufferContext)(qpGeomVertexArrayData *data);
 
   // This is the GL "name" of the data object.
   GLuint _index;
@@ -36,9 +36,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    DataContext::init_type();
-    register_type(_type_handle, CLASSPREFIX_QUOTED "DataContext",
-                  DataContext::get_class_type());
+    VertexBufferContext::init_type();
+    register_type(_type_handle, CLASSPREFIX_QUOTED "VertexBufferContext",
+                  VertexBufferContext::get_class_type());
   }
   virtual TypeHandle get_type() const {
     return get_class_type();
@@ -49,5 +49,5 @@ private:
   static TypeHandle _type_handle;
 };
 
-#include "glDataContext_src.I"
+#include "glVertexBufferContext_src.I"
 

+ 2 - 1
panda/src/glstuff/glmisc_src.cxx

@@ -63,7 +63,8 @@ void CLP(init_classes)() {
   CLP(GraphicsStateGuardian)::init_type();
   CLP(TextureContext)::init_type();
   CLP(GeomContext)::init_type();
-  CLP(DataContext)::init_type();
+  CLP(VertexBufferContext)::init_type();
+  CLP(IndexBufferContext)::init_type();
 
   PandaSystem *ps = PandaSystem::get_global_ptr();
   ps->add_system(GLSYSTEM_NAME);

+ 2 - 1
panda/src/glstuff/glstuff_src.cxx

@@ -23,7 +23,8 @@
 
 #include "glmisc_src.cxx"
 #include "glTextureContext_src.cxx"
-#include "glDataContext_src.cxx"
+#include "glVertexBufferContext_src.cxx"
+#include "glIndexBufferContext_src.cxx"
 #include "glGeomContext_src.cxx"
 #include "glGeomMunger_src.cxx"
 #include "glCgShaderContext_src.cxx"

+ 2 - 1
panda/src/glstuff/glstuff_src.h

@@ -41,7 +41,8 @@
 
 #include "glmisc_src.h"
 #include "glTextureContext_src.h"
-#include "glDataContext_src.h"
+#include "glVertexBufferContext_src.h"
+#include "glIndexBufferContext_src.h"
 #include "glGeomContext_src.h"
 #include "glGeomMunger_src.h"
 #include "glCgShaderContext_src.h"

+ 12 - 6
panda/src/gobj/Sources.pp

@@ -12,7 +12,6 @@
   #define SOURCES \
     boundedObject.I boundedObject.h \
     config_gobj.h \
-    dataContext.I dataContext.h \
     drawable.h \
     geom.I geom.h \
     geomContext.I geomContext.h \
@@ -25,6 +24,7 @@
     qpgeomTriangles.h \
     qpgeomTristrips.h \
     qpgeomTrifans.h \
+    qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
     qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
@@ -32,6 +32,7 @@
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
     qpgeomVertexIterator.h qpgeomVertexIterator.I \
+    indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     material.I material.h materialPool.I materialPool.h  \
     matrixLens.I matrixLens.h \
@@ -43,12 +44,12 @@
     texture.I texture.h \
     textureContext.I textureContext.h \
     texturePool.I texturePool.h \
-    textureStage.I textureStage.h
+    textureStage.I textureStage.h \
+    vertexBufferContext.I vertexBufferContext.h
     
   #define INCLUDED_SOURCES \
     boundedObject.cxx \
     config_gobj.cxx \
-    dataContext.cxx \
     drawable.cxx geom.cxx  \
     geomContext.cxx \
     geomLine.cxx geomLinestrip.cxx geomPoint.cxx geomPolygon.cxx  \
@@ -67,6 +68,7 @@
     qpgeomVertexDataType.cxx \
     qpgeomVertexFormat.cxx \
     qpgeomVertexIterator.cxx \
+    indexBufferContext.cxx \
     material.cxx  \
     internalName.cxx \
     materialPool.cxx matrixLens.cxx orthographicLens.cxx  \
@@ -74,12 +76,12 @@
     preparedGraphicsObjects.cxx \
     lens.cxx  \
     savedContext.cxx texture.cxx textureContext.cxx texturePool.cxx \
-    textureStage.cxx
+    textureStage.cxx \
+    vertexBufferContext.cxx
 
   #define INSTALL_HEADERS \
     boundedObject.I boundedObject.h \
     config_gobj.h \
-    dataContext.I dataContext.h \
     drawable.h geom.I geom.h \
     textureContext.I textureContext.h \
     geomLine.h \
@@ -92,6 +94,7 @@
     qpgeomTriangles.h \
     qpgeomTristrips.h \
     qpgeomTrifans.h \
+    qpgeomUsageHint.h \
     qpgeomVertexArrayData.h qpgeomVertexArrayData.I \
     qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
     qpgeomVertexCacheManager.h qpgeomVertexCacheManager.I \
@@ -99,6 +102,7 @@
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
     qpgeomVertexIterator.h qpgeomVertexIterator.I \
+    indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     material.I material.h \
     materialPool.I materialPool.h matrixLens.I matrixLens.h \
@@ -110,7 +114,9 @@
     texture.I texture.h \
     textureContext.I textureContext.h \
     texturePool.I texturePool.h \
-    textureStage.I textureStage.h
+    textureStage.I textureStage.h \
+    vertexBufferContext.I vertexBufferContext.h
+
 
   #define IGATESCAN all
 

+ 4 - 2
panda/src/gobj/config_gobj.cxx

@@ -41,7 +41,8 @@
 #include "textureStage.h"
 #include "textureContext.h"
 #include "geomContext.h"
-#include "dataContext.h"
+#include "vertexBufferContext.h"
+#include "indexBufferContext.h"
 #include "internalName.h"
 
 #include "dconfig.h"
@@ -182,7 +183,8 @@ ConfigureFn(config_gobj) {
   qpGeomVertexFormat::init_type();
   TextureContext::init_type();
   GeomContext::init_type();
-  DataContext::init_type();
+  VertexBufferContext::init_type();
+  IndexBufferContext::init_type();
   Material::init_type();
   OrthographicLens::init_type();
   MatrixLens::init_type();

+ 0 - 1
panda/src/gobj/gobj_composite1.cxx

@@ -1,6 +1,5 @@
 
 #include "boundedObject.cxx"
-#include "dataContext.cxx"
 #include "geom.cxx"
 #include "geomLine.cxx"
 #include "geomLinestrip.cxx"

+ 4 - 2
panda/src/gobj/gobj_composite2.cxx

@@ -2,16 +2,18 @@
 #include "config_gobj.cxx"
 #include "drawable.cxx"
 #include "geomContext.cxx"
+#include "indexBufferContext.cxx"
 #include "internalName.cxx"
+#include "lens.cxx"
 #include "material.cxx"
 #include "materialPool.cxx"
-#include "orthographicLens.cxx"
 #include "matrixLens.cxx"
+#include "orthographicLens.cxx"
 #include "perspectiveLens.cxx"
 #include "preparedGraphicsObjects.cxx"
-#include "lens.cxx"
 #include "savedContext.cxx"
 #include "texture.cxx"
 #include "textureContext.cxx"
 #include "texturePool.cxx"
 #include "textureStage.cxx"
+#include "vertexBufferContext.cxx"

+ 20 - 20
panda/src/gobj/dataContext.I → panda/src/gobj/indexBufferContext.I

@@ -1,4 +1,4 @@
-// Filename: dataContext.I
+// Filename: indexBufferContext.I
 // Created by:  drose (17Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -18,74 +18,74 @@
 
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DataContext::Constructor
+//     Function: IndexBufferContext::Constructor
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE DataContext::
-DataContext(qpGeomVertexArrayData *data) :
+INLINE IndexBufferContext::
+IndexBufferContext(qpGeomPrimitive *data) :
   _data(data),
   // Initially, the number of bytes is zero, until the data has been
   // loaded (and mark_loaded() is called).
-  _num_bytes(0)
+  _data_size_bytes(0)
 {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DataContext::get_data
+//     Function: IndexBufferContext::get_data
 //       Access: Public
 //  Description: Returns the pointer to the client-side array data
 //               object.
 ////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexArrayData *DataContext::
+INLINE qpGeomPrimitive *IndexBufferContext::
 get_data() const {
   return _data;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DataContext::get_num_bytes
+//     Function: IndexBufferContext::get_data_size_bytes
 //       Access: Public
 //  Description: Returns the number of bytes previously reported for
 //               the data object.  This is used to track changes in
 //               the data object's allocated size; if it changes from
 //               this, we need to create a new buffer.
 ////////////////////////////////////////////////////////////////////
-INLINE int DataContext::
-get_num_bytes() const {
-  return _num_bytes;
+INLINE int IndexBufferContext::
+get_data_size_bytes() const {
+  return _data_size_bytes;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DataContext::changed_size
+//     Function: IndexBufferContext::changed_size
 //       Access: Public
 //  Description: Returns true if the data has changed size since the
 //               last time mark_loaded() was called.
 ////////////////////////////////////////////////////////////////////
-INLINE bool DataContext::
+INLINE bool IndexBufferContext::
 changed_size() const {
-  return get_num_bytes() != _data->get_num_bytes();
+  return get_data_size_bytes() != _data->get_data_size_bytes();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DataContext::was_modified
+//     Function: IndexBufferContext::was_modified
 //       Access: Public
 //  Description: Returns true if the data has been modified since the
 //               last time mark_loaded() was called.
 ////////////////////////////////////////////////////////////////////
-INLINE bool DataContext::
+INLINE bool IndexBufferContext::
 was_modified() const {
   return _modified != _data->get_modified();
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: DataContext::mark_loaded
+//     Function: IndexBufferContext::mark_loaded
 //       Access: Public
-//  Description: Should be called after the DataContext has been
+//  Description: Should be called after the IndexBufferContext has been
 //               loaded into graphics memory, this updates the
 //               internal flags for changed_size() and modified().
 ////////////////////////////////////////////////////////////////////
-INLINE void DataContext::
+INLINE void IndexBufferContext::
 mark_loaded() {
-  _num_bytes = _data->get_num_bytes();
+  _data_size_bytes = _data->get_data_size_bytes();
   _modified = _data->get_modified();
 }

+ 21 - 0
panda/src/gobj/indexBufferContext.cxx

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

+ 82 - 0
panda/src/gobj/indexBufferContext.h

@@ -0,0 +1,82 @@
+// Filename: indexBufferContext.h
+// Created by:  drose (17Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef INDEXBUFFERCONTEXT_H
+#define INDEXBUFFERCONTEXT_H
+
+#include "pandabase.h"
+
+#include "savedContext.h"
+#include "updateSeq.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : IndexBufferContext
+// Description : This is a special class object that holds all the
+//               information returned by a particular GSG to indicate
+//               the vertex data array's internal context identifier.
+//
+//               This allows the GSG to cache the vertex data array in
+//               whatever way makes sense.  For instance, DirectX can
+//               allocate a vertex buffer for the array.  OpenGL can
+//               create a buffer object.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA IndexBufferContext : public SavedContext {
+public:
+  INLINE IndexBufferContext(qpGeomPrimitive *data);
+
+  INLINE qpGeomPrimitive *get_data() const;
+
+  INLINE int get_data_size_bytes() const;
+  INLINE bool changed_size() const;
+  INLINE bool was_modified() const;
+
+  INLINE void mark_loaded();
+
+private:
+  // This cannot be a PT(qpGeomPrimitive), because the data and
+  // the GSG both own their IndexBufferContexts!  That would create a
+  // circular reference count.
+  qpGeomPrimitive *_data;
+  UpdateSeq _modified;
+  int _data_size_bytes;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    SavedContext::init_type();
+    register_type(_type_handle, "IndexBufferContext",
+                  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;
+
+  friend class PreparedGraphicsObjects;
+};
+
+#include "indexBufferContext.I"
+
+#endif
+

+ 259 - 74
panda/src/gobj/preparedGraphicsObjects.cxx

@@ -18,9 +18,12 @@
 
 #include "preparedGraphicsObjects.h"
 #include "textureContext.h"
+#include "vertexBufferContext.h"
+#include "indexBufferContext.h"
 #include "texture.h"
 #include "geom.h"
 #include "qpgeomVertexArrayData.h"
+#include "qpgeomPrimitive.h"
 #include "mutexHolder.h"
 
 PStatCollector PreparedGraphicsObjects::_total_texusage_pcollector("Texture usage");
@@ -74,18 +77,31 @@ PreparedGraphicsObjects::
   _released_geoms.clear();
   _enqueued_geoms.clear();
 
-  Datas::iterator dci;
-  for (dci = _prepared_datas.begin();
-       dci != _prepared_datas.end();
-       ++dci) {
-    DataContext *dc = (*dci);
-    _total_texusage_pcollector.sub_level(dc->get_num_bytes());
-    dc->_data->clear_prepared(this);
+  VertexBuffers::iterator vbci;
+  for (vbci = _prepared_vertex_buffers.begin();
+       vbci != _prepared_vertex_buffers.end();
+       ++vbci) {
+    VertexBufferContext *vbc = (*vbci);
+    _total_texusage_pcollector.sub_level(vbc->get_data_size_bytes());
+    vbc->_data->clear_prepared(this);
   }
 
-  _prepared_datas.clear();
-  _released_datas.clear();
-  _enqueued_datas.clear();
+  _prepared_vertex_buffers.clear();
+  _released_vertex_buffers.clear();
+  _enqueued_vertex_buffers.clear();
+
+  IndexBuffers::iterator ibci;
+  for (ibci = _prepared_index_buffers.begin();
+       ibci != _prepared_index_buffers.end();
+       ++ibci) {
+    IndexBufferContext *ibc = (*ibci);
+    _total_texusage_pcollector.sub_level(ibc->get_data_size_bytes());
+    ibc->_data->clear_prepared(this);
+  }
+
+  _prepared_index_buffers.clear();
+  _released_index_buffers.clear();
+  _enqueued_index_buffers.clear();
 }
 
 
@@ -375,78 +391,78 @@ prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PreparedGraphicsObjects::enqueue_data
+//     Function: PreparedGraphicsObjects::enqueue_vertex_buffer
 //       Access: Public
-//  Description: Indicates that a data array would like to be put on the
+//  Description: Indicates that a buffer would like to be put on the
 //               list to be prepared when the GSG is next ready to
 //               do this (presumably at the next frame).
 ////////////////////////////////////////////////////////////////////
 void PreparedGraphicsObjects::
-enqueue_data(qpGeomVertexArrayData *data) {
+enqueue_vertex_buffer(qpGeomVertexArrayData *data) {
   MutexHolder holder(_lock);
 
-  _enqueued_datas.insert(data);
+  _enqueued_vertex_buffers.insert(data);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PreparedGraphicsObjects::dequeue_data
+//     Function: PreparedGraphicsObjects::dequeue_vertex_buffer
 //       Access: Public
-//  Description: Removes a data array from the queued list of data
+//  Description: Removes a buffer from the queued list of data
 //               arrays to be prepared.  Normally it is not necessary
 //               to call this, unless you change your mind about
 //               preparing it at the last minute, since the data will
 //               automatically be dequeued and prepared at the next
 //               frame.
 //
-//               The return value is true if the data array is
+//               The return value is true if the buffer is
 //               successfully dequeued, false if it had not been
 //               queued.
 ////////////////////////////////////////////////////////////////////
 bool PreparedGraphicsObjects::
-dequeue_data(qpGeomVertexArrayData *data) {
+dequeue_vertex_buffer(qpGeomVertexArrayData *data) {
   MutexHolder holder(_lock);
 
-  EnqueuedDatas::iterator qi = _enqueued_datas.find(data);
-  if (qi != _enqueued_datas.end()) {
-    _enqueued_datas.erase(qi);
+  EnqueuedVertexBuffers::iterator qi = _enqueued_vertex_buffers.find(data);
+  if (qi != _enqueued_vertex_buffers.end()) {
+    _enqueued_vertex_buffers.erase(qi);
     return true;
   }
   return false;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PreparedGraphicsObjects::release_data
+//     Function: PreparedGraphicsObjects::release_vertex_buffer
 //       Access: Public
 //  Description: Indicates that a data context, created by a
-//               previous call to prepare_data(), is no longer
+//               previous call to prepare_vertex_buffer(), is no longer
 //               needed.  The driver resources will not be freed until
 //               some GSG calls update(), indicating it is at a
 //               stage where it is ready to release datas--this
 //               prevents conflicts from threading or multiple GSG's
 //               sharing datas (we have no way of knowing which
 //               graphics context is currently active, or what state
-//               it's in, at the time release_data is called).
+//               it's in, at the time release_vertex_buffer is called).
 ////////////////////////////////////////////////////////////////////
 void PreparedGraphicsObjects::
-release_data(DataContext *dc) {
+release_vertex_buffer(VertexBufferContext *vbc) {
   MutexHolder holder(_lock);
 
-  dc->_data->clear_prepared(this);
-  _total_buffers_pcollector.sub_level(dc->get_num_bytes());
+  vbc->_data->clear_prepared(this);
+  _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
 
   // We have to set the Data pointer to NULL at this point, since
   // the Data itself might destruct at any time after it has been
   // released.
-  dc->_data = (qpGeomVertexArrayData *)NULL;
+  vbc->_data = (qpGeomVertexArrayData *)NULL;
 
-  bool removed = (_prepared_datas.erase(dc) != 0);
+  bool removed = (_prepared_vertex_buffers.erase(vbc) != 0);
   nassertv(removed);
 
-  _released_datas.insert(dc);
+  _released_vertex_buffers.insert(vbc);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PreparedGraphicsObjects::release_all_datas
+//     Function: PreparedGraphicsObjects::release_all_vertex_buffers
 //       Access: Public
 //  Description: Releases all datas at once.  This will force them
 //               to be reloaded into data memory for all GSG's that
@@ -454,71 +470,218 @@ release_data(DataContext *dc) {
 //               released.
 ////////////////////////////////////////////////////////////////////
 int PreparedGraphicsObjects::
-release_all_datas() {
+release_all_vertex_buffers() {
   MutexHolder holder(_lock);
 
-  int num_datas = (int)_prepared_datas.size();
+  int num_vertex_buffers = (int)_prepared_vertex_buffers.size();
 
-  Datas::iterator dci;
-  for (dci = _prepared_datas.begin();
-       dci != _prepared_datas.end();
-       ++dci) {
-    DataContext *dc = (*dci);
-    dc->_data->clear_prepared(this);
-    _total_buffers_pcollector.sub_level(dc->get_num_bytes());
-    dc->_data = (qpGeomVertexArrayData *)NULL;
+  VertexBuffers::iterator vbci;
+  for (vbci = _prepared_vertex_buffers.begin();
+       vbci != _prepared_vertex_buffers.end();
+       ++vbci) {
+    VertexBufferContext *vbc = (*vbci);
+    vbc->_data->clear_prepared(this);
+    _total_buffers_pcollector.sub_level(vbc->get_data_size_bytes());
+    vbc->_data = (qpGeomVertexArrayData *)NULL;
 
-    _released_datas.insert(dc);
+    _released_vertex_buffers.insert(vbc);
   }
 
-  _prepared_datas.clear();
+  _prepared_vertex_buffers.clear();
 
-  return num_datas;
+  return num_vertex_buffers;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: PreparedGraphicsObjects::prepare_data_now
+//     Function: PreparedGraphicsObjects::prepare_vertex_buffer_now
 //       Access: Public
-//  Description: Immediately creates a new DataContext for the
+//  Description: Immediately creates a new VertexBufferContext for the
 //               indicated data and returns it.  This assumes that
 //               the GraphicsStateGuardian is the currently active
 //               rendering context and that it is ready to accept new
 //               datas.  If this is not necessarily the case, you
-//               should use enqueue_data() instead.
+//               should use enqueue_vertex_buffer() instead.
 //
 //               Normally, this function is not called directly.  Call
 //               Data::prepare_now() instead.
 //
-//               The DataContext contains all of the pertinent
+//               The VertexBufferContext contains all of the pertinent
 //               information needed by the GSG to keep track of this
 //               one particular data, and will exist as long as the
 //               data is ready to be rendered.
 //
 //               When either the Data or the
 //               PreparedGraphicsObjects object destructs, the
-//               DataContext will be deleted.
+//               VertexBufferContext will be deleted.
 ////////////////////////////////////////////////////////////////////
-DataContext *PreparedGraphicsObjects::
-prepare_data_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) {
+VertexBufferContext *PreparedGraphicsObjects::
+prepare_vertex_buffer_now(qpGeomVertexArrayData *data, GraphicsStateGuardianBase *gsg) {
   MutexHolder holder(_lock);
 
-  // Ask the GSG to create a brand new DataContext.  There might
+  // Ask the GSG to create a brand new VertexBufferContext.  There might
   // be several GSG's sharing the same set of datas; if so, it
   // doesn't matter which of them creates the context (since they're
   // all shared anyway).
-  DataContext *dc = gsg->prepare_data(data);
+  VertexBufferContext *vbc = gsg->prepare_vertex_buffer(data);
 
-  if (dc != (DataContext *)NULL) {
-    bool prepared = _prepared_datas.insert(dc).second;
-    nassertr(prepared, dc);
+  if (vbc != (VertexBufferContext *)NULL) {
+    bool prepared = _prepared_vertex_buffers.insert(vbc).second;
+    nassertr(prepared, vbc);
 
     // The size has already been counted by
-    // GraphicsStateGuardian::add_to_data_record(); we don't need to
+    // GraphicsStateGuardian::add_to_vertex_buffer_record(); we don't need to
     // count it again here.
-    //_total_buffers_pcollector.add_level(dc->get_num_bytes());
+    //_total_buffers_pcollector.add_level(vbc->get_data_size_bytes());
   }
 
-  return dc;
+  return vbc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::enqueue_index_buffer
+//       Access: Public
+//  Description: Indicates that a buffer would like to be put on the
+//               list to be prepared when the GSG is next ready to
+//               do this (presumably at the next frame).
+////////////////////////////////////////////////////////////////////
+void PreparedGraphicsObjects::
+enqueue_index_buffer(qpGeomPrimitive *data) {
+  MutexHolder holder(_lock);
+
+  _enqueued_index_buffers.insert(data);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::dequeue_index_buffer
+//       Access: Public
+//  Description: Removes a buffer from the queued list of data
+//               arrays to be prepared.  Normally it is not necessary
+//               to call this, unless you change your mind about
+//               preparing it at the last minute, since the data will
+//               automatically be dequeued and prepared at the next
+//               frame.
+//
+//               The return value is true if the buffer is
+//               successfully dequeued, false if it had not been
+//               queued.
+////////////////////////////////////////////////////////////////////
+bool PreparedGraphicsObjects::
+dequeue_index_buffer(qpGeomPrimitive *data) {
+  MutexHolder holder(_lock);
+
+  EnqueuedIndexBuffers::iterator qi = _enqueued_index_buffers.find(data);
+  if (qi != _enqueued_index_buffers.end()) {
+    _enqueued_index_buffers.erase(qi);
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::release_index_buffer
+//       Access: Public
+//  Description: Indicates that a data context, created by a
+//               previous call to prepare_index_buffer(), is no longer
+//               needed.  The driver resources will not be freed until
+//               some GSG calls update(), indicating it is at a
+//               stage where it is ready to release datas--this
+//               prevents conflicts from threading or multiple GSG's
+//               sharing datas (we have no way of knowing which
+//               graphics context is currently active, or what state
+//               it's in, at the time release_index_buffer is called).
+////////////////////////////////////////////////////////////////////
+void PreparedGraphicsObjects::
+release_index_buffer(IndexBufferContext *ibc) {
+  MutexHolder holder(_lock);
+
+  ibc->_data->clear_prepared(this);
+  _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
+
+  // We have to set the Data pointer to NULL at this point, since
+  // the Data itself might destruct at any time after it has been
+  // released.
+  ibc->_data = (qpGeomPrimitive *)NULL;
+
+  bool removed = (_prepared_index_buffers.erase(ibc) != 0);
+  nassertv(removed);
+
+  _released_index_buffers.insert(ibc);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::release_all_index_buffers
+//       Access: Public
+//  Description: Releases all datas at once.  This will force them
+//               to be reloaded into data memory for all GSG's that
+//               share this object.  Returns the number of datas
+//               released.
+////////////////////////////////////////////////////////////////////
+int PreparedGraphicsObjects::
+release_all_index_buffers() {
+  MutexHolder holder(_lock);
+
+  int num_index_buffers = (int)_prepared_index_buffers.size();
+
+  IndexBuffers::iterator ibci;
+  for (ibci = _prepared_index_buffers.begin();
+       ibci != _prepared_index_buffers.end();
+       ++ibci) {
+    IndexBufferContext *ibc = (*ibci);
+    ibc->_data->clear_prepared(this);
+    _total_buffers_pcollector.sub_level(ibc->get_data_size_bytes());
+    ibc->_data = (qpGeomPrimitive *)NULL;
+
+    _released_index_buffers.insert(ibc);
+  }
+
+  _prepared_index_buffers.clear();
+
+  return num_index_buffers;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PreparedGraphicsObjects::prepare_index_buffer_now
+//       Access: Public
+//  Description: Immediately creates a new IndexBufferContext for the
+//               indicated data and returns it.  This assumes that
+//               the GraphicsStateGuardian is the currently active
+//               rendering context and that it is ready to accept new
+//               datas.  If this is not necessarily the case, you
+//               should use enqueue_index_buffer() instead.
+//
+//               Normally, this function is not called directly.  Call
+//               Data::prepare_now() instead.
+//
+//               The IndexBufferContext contains all of the pertinent
+//               information needed by the GSG to keep track of this
+//               one particular data, and will exist as long as the
+//               data is ready to be rendered.
+//
+//               When either the Data or the
+//               PreparedGraphicsObjects object destructs, the
+//               IndexBufferContext will be deleted.
+////////////////////////////////////////////////////////////////////
+IndexBufferContext *PreparedGraphicsObjects::
+prepare_index_buffer_now(qpGeomPrimitive *data, GraphicsStateGuardianBase *gsg) {
+  MutexHolder holder(_lock);
+
+  // Ask the GSG to create a brand new IndexBufferContext.  There might
+  // be several GSG's sharing the same set of datas; if so, it
+  // doesn't matter which of them creates the context (since they're
+  // all shared anyway).
+  IndexBufferContext *ibc = gsg->prepare_index_buffer(data);
+
+  if (ibc != (IndexBufferContext *)NULL) {
+    bool prepared = _prepared_index_buffers.insert(ibc).second;
+    nassertr(prepared, ibc);
+
+    // The size has already been counted by
+    // GraphicsStateGuardian::add_to_index_buffer_record(); we don't need to
+    // count it again here.
+    //_total_buffers_pcollector.add_level(ibc->get_data_size_bytes());
+  }
+
+  return ibc;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -537,7 +700,7 @@ void PreparedGraphicsObjects::
 update(GraphicsStateGuardianBase *gsg) {
   MutexHolder holder(_lock);
 
-  // First, release all the textures, geoms, and data arrays awaiting
+  // First, release all the textures, geoms, and buffers awaiting
   // release.
   Textures::iterator tci;
   for (tci = _released_textures.begin();
@@ -559,17 +722,27 @@ update(GraphicsStateGuardianBase *gsg) {
 
   _released_geoms.clear();
 
-  Datas::iterator dci;
-  for (dci = _released_datas.begin();
-       dci != _released_datas.end();
-       ++dci) {
-    DataContext *dc = (*dci);
-    gsg->release_data(dc);
+  VertexBuffers::iterator vbci;
+  for (vbci = _released_vertex_buffers.begin();
+       vbci != _released_vertex_buffers.end();
+       ++vbci) {
+    VertexBufferContext *vbc = (*vbci);
+    gsg->release_vertex_buffer(vbc);
+  }
+
+  _released_vertex_buffers.clear();
+
+  IndexBuffers::iterator ibci;
+  for (ibci = _released_index_buffers.begin();
+       ibci != _released_index_buffers.end();
+       ++ibci) {
+    IndexBufferContext *ibc = (*ibci);
+    gsg->release_index_buffer(ibc);
   }
 
-  _released_datas.clear();
+  _released_index_buffers.clear();
 
-  // Now prepare all the textures, geoms, and data arrays awaiting
+  // Now prepare all the textures, geoms, and buffers awaiting
   // preparation.
   EnqueuedTextures::iterator qti;
   for (qti = _enqueued_textures.begin();
@@ -589,13 +762,25 @@ update(GraphicsStateGuardianBase *gsg) {
     geom->prepare_now(this, gsg);
   }
 
-  EnqueuedDatas::iterator qdi;
-  for (qdi = _enqueued_datas.begin();
-       qdi != _enqueued_datas.end();
-       ++qdi) {
-    qpGeomVertexArrayData *data = (*qdi);
+  _enqueued_geoms.clear();
+
+  EnqueuedVertexBuffers::iterator qvbi;
+  for (qvbi = _enqueued_vertex_buffers.begin();
+       qvbi != _enqueued_vertex_buffers.end();
+       ++qvbi) {
+    qpGeomVertexArrayData *data = (*qvbi);
+    data->prepare_now(this, gsg);
+  }
+
+  _enqueued_vertex_buffers.clear();
+
+  EnqueuedIndexBuffers::iterator qibi;
+  for (qibi = _enqueued_index_buffers.begin();
+       qibi != _enqueued_index_buffers.end();
+       ++qibi) {
+    qpGeomPrimitive *data = (*qibi);
     data->prepare_now(this, gsg);
   }
 
-  _enqueued_datas.clear();
+  _enqueued_index_buffers.clear();
 }

+ 27 - 11
panda/src/gobj/preparedGraphicsObjects.h

@@ -24,6 +24,7 @@
 #include "texture.h"
 #include "geom.h"
 #include "qpgeomVertexArrayData.h"
+#include "qpgeomPrimitive.h"
 #include "pointerTo.h"
 #include "pStatCollector.h"
 #include "pset.h"
@@ -31,7 +32,8 @@
 
 class TextureContext;
 class GeomContext;
-class DataContext;
+class VertexBufferContext;
+class IndexBufferContext;
 class GraphicsStateGuardianBase;
 
 ////////////////////////////////////////////////////////////////////
@@ -72,13 +74,23 @@ public:
 
   GeomContext *prepare_geom_now(Geom *geom, GraphicsStateGuardianBase *gsg);
 
-  void enqueue_data(qpGeomVertexArrayData *data);
-  bool dequeue_data(qpGeomVertexArrayData *data);
-  void release_data(DataContext *gc);
-  int release_all_datas();
+  void enqueue_vertex_buffer(qpGeomVertexArrayData *data);
+  bool dequeue_vertex_buffer(qpGeomVertexArrayData *data);
+  void release_vertex_buffer(VertexBufferContext *vbc);
+  int release_all_vertex_buffers();
 
-  DataContext *prepare_data_now(qpGeomVertexArrayData *data,
-                                GraphicsStateGuardianBase *gsg);
+  VertexBufferContext *
+  prepare_vertex_buffer_now(qpGeomVertexArrayData *data,
+                            GraphicsStateGuardianBase *gsg);
+
+  void enqueue_index_buffer(qpGeomPrimitive *data);
+  bool dequeue_index_buffer(qpGeomPrimitive *data);
+  void release_index_buffer(IndexBufferContext *ibc);
+  int release_all_index_buffers();
+
+  IndexBufferContext *
+  prepare_index_buffer_now(qpGeomPrimitive *data,
+                           GraphicsStateGuardianBase *gsg);
 
   void update(GraphicsStateGuardianBase *gsg);
 
@@ -87,16 +99,20 @@ private:
   typedef phash_set< PT(Texture) > EnqueuedTextures;
   typedef phash_set<GeomContext *, pointer_hash> Geoms;
   typedef phash_set< PT(Geom) > EnqueuedGeoms;
-  typedef phash_set<DataContext *, pointer_hash> Datas;
-  typedef phash_set< PT(qpGeomVertexArrayData) > EnqueuedDatas;
+  typedef phash_set<VertexBufferContext *, pointer_hash> VertexBuffers;
+  typedef phash_set< PT(qpGeomVertexArrayData) > EnqueuedVertexBuffers;
+  typedef phash_set<IndexBufferContext *, pointer_hash> IndexBuffers;
+  typedef phash_set< PT(qpGeomPrimitive) > EnqueuedIndexBuffers;
 
   Mutex _lock;
   Textures _prepared_textures, _released_textures;  
   EnqueuedTextures _enqueued_textures;
   Geoms _prepared_geoms, _released_geoms;  
   EnqueuedGeoms _enqueued_geoms;
-  Datas _prepared_datas, _released_datas;  
-  EnqueuedDatas _enqueued_datas;
+  VertexBuffers _prepared_vertex_buffers, _released_vertex_buffers;  
+  EnqueuedVertexBuffers _enqueued_vertex_buffers;
+  IndexBuffers _prepared_index_buffers, _released_index_buffers;  
+  EnqueuedIndexBuffers _enqueued_index_buffers;
 
   static PStatCollector _total_texusage_pcollector;
   static PStatCollector _total_buffers_pcollector;

+ 46 - 0
panda/src/gobj/qpgeomPrimitive.I

@@ -17,6 +17,27 @@
 ////////////////////////////////////////////////////////////////////
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_usage_hint
+//       Access: Published
+//  Description: Returns the usage hint for this primitive.  See
+//               GeomUsageHint.  This has nothing to do with the usage
+//               hint associated with the primitive's vertices; this
+//               only specifies how often the vertex indices that
+//               define the primitive will be modified.
+//
+//               It is perfectly legal (and, in fact, common) for a
+//               GeomPrimitive to have UH_static on itself, while
+//               referencing vertex data with UH_dynamic.  This means
+//               that the vertices themselves will be animated, but
+//               the primitive will always reference the same set of
+//               vertices from the pool.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomUsageHint::UsageHint qpGeomPrimitive::
+get_usage_hint() const {
+  return _usage_hint;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_shade_model
 //       Access: Published
@@ -196,6 +217,31 @@ get_maxs() const {
   return cdata->_maxs;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_data_size_bytes
+//       Access: Published
+//  Description: Returns the number of bytes stored in the vertices
+//               array.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_data_size_bytes() const {
+  CDReader cdata(_cycler);
+  return cdata->_vertices.size() * sizeof(short);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_modified
+//       Access: Published
+//  Description: Returns a sequence number which is guaranteed to
+//               change at least every time the vertex index array is
+//               modified.
+////////////////////////////////////////////////////////////////////
+INLINE UpdateSeq qpGeomPrimitive::
+get_modified() const {
+  CDReader cdata(_cycler);
+  return cdata->_modified;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_min_vertex
 //       Access: Published

+ 135 - 1
panda/src/gobj/qpgeomPrimitive.cxx

@@ -21,6 +21,7 @@
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexDataType.h"
 #include "qpgeomVertexCacheManager.h"
+#include "preparedGraphicsObjects.h"
 #include "internalName.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -36,7 +37,9 @@ PStatCollector qpGeomPrimitive::_rotate_pcollector("Draw:Rotate");
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 qpGeomPrimitive::
-qpGeomPrimitive() {
+qpGeomPrimitive(qpGeomUsageHint::UsageHint usage_hint) :
+  _usage_hint(usage_hint)
+{
 }
  
 ////////////////////////////////////////////////////////////////////
@@ -47,6 +50,7 @@ qpGeomPrimitive() {
 qpGeomPrimitive::
 qpGeomPrimitive(const qpGeomPrimitive &copy) :
   TypedWritableReferenceCount(copy),
+  _usage_hint(copy._usage_hint),
   _cycler(copy._cycler)
 {
 }
@@ -75,6 +79,8 @@ qpGeomPrimitive::
       _cycler.release_write_stage(i, cdata);
     }
   }
+
+  release_all();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -527,6 +533,134 @@ clear_cache() {
     cache_mgr->remove_primitive(this);
     cdata->_decomposed = NULL;
   }
+
+  // This, on the other hand, should be applied to the current
+  // pipeline stage.
+  ++(cdata->_modified);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::prepare
+//       Access: Published
+//  Description: Indicates that the data should be enqueued to be
+//               prepared in the indicated prepared_objects at the
+//               beginning of the next frame.  This will ensure the
+//               data is already loaded into the GSG if it is expected
+//               to be rendered soon.
+//
+//               Use this function instead of prepare_now() to preload
+//               datas from a user interface standpoint.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+prepare(PreparedGraphicsObjects *prepared_objects) {
+  prepared_objects->enqueue_index_buffer(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::prepare_now
+//       Access: Public
+//  Description: Creates a context for the data on the particular
+//               GSG, if it does not already exist.  Returns the new
+//               (or old) IndexBufferContext.  This assumes that the
+//               GraphicsStateGuardian is the currently active
+//               rendering context and that it is ready to accept new
+//               datas.  If this is not necessarily the case, you
+//               should use prepare() instead.
+//
+//               Normally, this is not called directly except by the
+//               GraphicsStateGuardian; a data does not need to be
+//               explicitly prepared by the user before it may be
+//               rendered.
+////////////////////////////////////////////////////////////////////
+IndexBufferContext *qpGeomPrimitive::
+prepare_now(PreparedGraphicsObjects *prepared_objects, 
+            GraphicsStateGuardianBase *gsg) {
+  Contexts::const_iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    return (*ci).second;
+  }
+
+  IndexBufferContext *ibc = prepared_objects->prepare_index_buffer_now(this, gsg);
+  if (ibc != (IndexBufferContext *)NULL) {
+    _contexts[prepared_objects] = ibc;
+  }
+  return ibc;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::release
+//       Access: Public
+//  Description: Frees the data context only on the indicated object,
+//               if it exists there.  Returns true if it was released,
+//               false if it had not been prepared.
+////////////////////////////////////////////////////////////////////
+bool qpGeomPrimitive::
+release(PreparedGraphicsObjects *prepared_objects) {
+  Contexts::iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    IndexBufferContext *ibc = (*ci).second;
+    prepared_objects->release_index_buffer(ibc);
+    return true;
+  }
+
+  // Maybe it wasn't prepared yet, but it's about to be.
+  return prepared_objects->dequeue_index_buffer(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::release_all
+//       Access: Public
+//  Description: Frees the context allocated on all objects for which
+//               the data has been declared.  Returns the number of
+//               contexts which have been freed.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+release_all() {
+  // We have to traverse a copy of the _contexts list, because the
+  // PreparedGraphicsObjects object will call clear_prepared() in response
+  // to each release_index_buffer(), and we don't want to be modifying the
+  // _contexts list while we're traversing it.
+  Contexts temp = _contexts;
+  int num_freed = (int)_contexts.size();
+
+  Contexts::const_iterator ci;
+  for (ci = temp.begin(); ci != temp.end(); ++ci) {
+    PreparedGraphicsObjects *prepared_objects = (*ci).first;
+    IndexBufferContext *ibc = (*ci).second;
+    prepared_objects->release_index_buffer(ibc);
+  }
+
+  // Now that we've called release_index_buffer() on every known context,
+  // the _contexts list should have completely emptied itself.
+  nassertr(_contexts.empty(), num_freed);
+
+  return num_freed;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::clear_prepared
+//       Access: Private
+//  Description: Removes the indicated PreparedGraphicsObjects table
+//               from the data array's table, without actually
+//               releasing the data array.  This is intended to be
+//               called only from
+//               PreparedGraphicsObjects::release_index_buffer(); it should
+//               never be called by user code.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+clear_prepared(PreparedGraphicsObjects *prepared_objects) {
+  Contexts::iterator ci;
+  ci = _contexts.find(prepared_objects);
+  if (ci != _contexts.end()) {
+    _contexts.erase(ci);
+  } else {
+    // If this assertion fails, clear_prepared() was given a
+    // prepared_objects which the data array didn't know about.
+    nassertv(false);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 32 - 2
panda/src/gobj/qpgeomPrimitive.h

@@ -20,8 +20,10 @@
 #define qpGEOMPRIMITIVE_H
 
 #include "pandabase.h"
+#include "qpgeomUsageHint.h"
 #include "typedWritableReferenceCount.h"
 #include "luse.h"
+#include "updateSeq.h"
 #include "pointerTo.h"
 #include "pta_ushort.h"
 #include "pta_int.h"
@@ -32,8 +34,9 @@
 #include "pipelineCycler.h"
 
 class qpGeomVertexData;
+class PreparedGraphicsObjects;
+class IndexBufferContext;
 class GraphicsStateGuardianBase;
-class GeomContext;
 class FactoryParams;
 
 ////////////////////////////////////////////////////////////////////
@@ -61,7 +64,7 @@ class FactoryParams;
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomPrimitive : public TypedWritableReferenceCount {
 PUBLISHED:
-  qpGeomPrimitive();
+  qpGeomPrimitive(qpGeomUsageHint::UsageHint usage_hint);
   qpGeomPrimitive(const qpGeomPrimitive &copy);
   virtual ~qpGeomPrimitive();
 
@@ -88,6 +91,8 @@ PUBLISHED:
     SM_flat_last_vertex,
   };
 
+  INLINE qpGeomUsageHint::UsageHint get_usage_hint() const;
+
   INLINE ShadeModel get_shade_model() const;
   INLINE void set_shade_model(ShadeModel shade_model);
 
@@ -112,6 +117,8 @@ PUBLISHED:
   INLINE CPTA_ushort get_maxs() const;
 
   int get_num_bytes() const;
+  INLINE int get_data_size_bytes() const;
+  INLINE UpdateSeq get_modified() const;
 
   INLINE int get_min_vertex() const;
   INLINE int get_min_vertex(int i) const;
@@ -132,6 +139,17 @@ PUBLISHED:
 
   void clear_cache();
 
+  void prepare(PreparedGraphicsObjects *prepared_objects);
+
+public:
+  IndexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects, 
+                                  GraphicsStateGuardianBase *gsg);
+  bool release(PreparedGraphicsObjects *prepared_objects);
+  int release_all();
+
+private:
+  void clear_prepared(PreparedGraphicsObjects *prepared_objects);
+
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const=0;
 
@@ -151,6 +169,16 @@ protected:
   static PStatCollector _rotate_pcollector;
 
 private:
+  qpGeomUsageHint::UsageHint _usage_hint;
+
+  // A GeomPrimitive keeps a list (actually, a map) of all the
+  // PreparedGraphicsObjects tables that it has been prepared into.
+  // Each PGO conversely keeps a list (a set) of all the Geoms that
+  // have been prepared there.  When either destructs, it removes
+  // itself from the other's list.
+  typedef pmap<PreparedGraphicsObjects *, IndexBufferContext *> Contexts;
+  Contexts _contexts;
+
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
   public:
@@ -167,6 +195,7 @@ private:
     PTA_int _ends;
     PTA_ushort _mins;
     PTA_ushort _maxs;
+    UpdateSeq _modified;
 
     bool _got_minmax;
     unsigned short _min_vertex;
@@ -206,6 +235,7 @@ private:
 
   friend class qpGeom;
   friend class qpGeomVertexCacheManager;
+  friend class PreparedGraphicsObjects;
 };
 
 #include "qpgeomPrimitive.I"

+ 4 - 2
panda/src/gobj/qpgeomTriangles.cxx

@@ -29,7 +29,9 @@ TypeHandle qpGeomTriangles::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 qpGeomTriangles::
-qpGeomTriangles() {
+qpGeomTriangles(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
 }
  
 ////////////////////////////////////////////////////////////////////
@@ -158,7 +160,7 @@ register_with_read_factory() {
 ////////////////////////////////////////////////////////////////////
 TypedWritable *qpGeomTriangles::
 make_from_bam(const FactoryParams &params) {
-  qpGeomTriangles *object = new qpGeomTriangles;
+  qpGeomTriangles *object = new qpGeomTriangles(qpGeomUsageHint::UH_client);
   DatagramIterator scan;
   BamReader *manager;
 

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

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomTriangles : public qpGeomPrimitive {
 PUBLISHED:
-  qpGeomTriangles();
+  qpGeomTriangles(qpGeomUsageHint::UsageHint usage_hint);
   qpGeomTriangles(const qpGeomTriangles &copy);
   virtual ~qpGeomTriangles();
 

+ 5 - 3
panda/src/gobj/qpgeomTrifans.cxx

@@ -29,7 +29,9 @@ TypeHandle qpGeomTrifans::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 qpGeomTrifans::
-qpGeomTrifans() {
+qpGeomTrifans(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
 }
  
 ////////////////////////////////////////////////////////////////////
@@ -89,7 +91,7 @@ draw(GraphicsStateGuardianBase *gsg) const {
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomPrimitive) qpGeomTrifans::
 decompose_impl() const {
-  PT(qpGeomTriangles) triangles = new qpGeomTriangles;
+  PT(qpGeomTriangles) triangles = new qpGeomTriangles(get_usage_hint());
   triangles->set_shade_model(get_shade_model());
   CPTA_ushort vertices = get_vertices();
   CPTA_int ends = get_ends();
@@ -154,7 +156,7 @@ register_with_read_factory() {
 ////////////////////////////////////////////////////////////////////
 TypedWritable *qpGeomTrifans::
 make_from_bam(const FactoryParams &params) {
-  qpGeomTrifans *object = new qpGeomTrifans;
+  qpGeomTrifans *object = new qpGeomTrifans(qpGeomUsageHint::UH_client);
   DatagramIterator scan;
   BamReader *manager;
 

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

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomTrifans : public qpGeomPrimitive {
 PUBLISHED:
-  qpGeomTrifans();
+  qpGeomTrifans(qpGeomUsageHint::UsageHint usage_hint);
   qpGeomTrifans(const qpGeomTrifans &copy);
   virtual ~qpGeomTrifans();
 

+ 5 - 3
panda/src/gobj/qpgeomTristrips.cxx

@@ -30,7 +30,9 @@ TypeHandle qpGeomTristrips::_type_handle;
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 qpGeomTristrips::
-qpGeomTristrips() {
+qpGeomTristrips(qpGeomUsageHint::UsageHint usage_hint) :
+  qpGeomPrimitive(usage_hint)
+{
 }
  
 ////////////////////////////////////////////////////////////////////
@@ -90,7 +92,7 @@ draw(GraphicsStateGuardianBase *gsg) const {
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomPrimitive) qpGeomTristrips::
 decompose_impl() const {
-  PT(qpGeomTriangles) triangles = new qpGeomTriangles;
+  PT(qpGeomTriangles) triangles = new qpGeomTriangles(get_usage_hint());
   triangles->set_shade_model(get_shade_model());
   CPTA_ushort vertices = get_vertices();
   CPTA_int ends = get_ends();
@@ -240,7 +242,7 @@ register_with_read_factory() {
 ////////////////////////////////////////////////////////////////////
 TypedWritable *qpGeomTristrips::
 make_from_bam(const FactoryParams &params) {
-  qpGeomTristrips *object = new qpGeomTristrips;
+  qpGeomTristrips *object = new qpGeomTristrips(qpGeomUsageHint::UH_client);
   DatagramIterator scan;
   BamReader *manager;
 

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

@@ -30,7 +30,7 @@
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomTristrips : public qpGeomPrimitive {
 PUBLISHED:
-  qpGeomTristrips();
+  qpGeomTristrips(qpGeomUsageHint::UsageHint usage_hint);
   qpGeomTristrips(const qpGeomTristrips &copy);
   virtual ~qpGeomTristrips();
 

+ 77 - 0
panda/src/gobj/qpgeomUsageHint.h

@@ -0,0 +1,77 @@
+// Filename: qpgeomUsageHint.h
+// Created by:  drose (18Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef qpGEOMUSAGEHINT_H
+#define qpGEOMUSAGEHINT_H
+
+#include "pandabase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomUsageHint
+// Description : This class exists just to provide scoping for the
+//               UsageHint enumerated type, which is used by
+//               GeomVertexData, GeomVertexArrayData, and
+//               GeomPrimitive.
+//
+//               The usage hint describes to the rendering backend how
+//               often the data in question will be modified and/or
+//               rendered.  It allows the backend to make appropriate
+//               choices about what part of memory the data should be
+//               stored in.
+//
+//               The hint is provided as a performance optimization
+//               only, and does not constraing actual usage; although
+//               it may be an important optimization.
+//
+//               In general, the hint may only be specified at the
+//               time the data object is constructed.  If you need to
+//               change it, you must create a new object (but in many
+//               cases you can just assign the same internal data
+//               pointer to the new object, to keep the same
+//               client-side memory).
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomUsageHint {
+PUBLISHED:
+  enum UsageHint {
+    // UH_client: don't attempt to upload the data; always keep it on
+    // the client.
+    UH_client,
+
+    // UH_stream: the data will be created once, used to render a few
+    // times, and then discarded.  This should be used for short-lived
+    // temporary arrays.
+    UH_stream,
+
+    // UH_static: the data will be created once, and used to render
+    // many times, without modification.  This is the most common
+    // case, since typically vertex data is not directly animated
+    // (this is not related to scene graph animation, e.g. from
+    // adjusting transforms on a node).
+    UH_static,
+
+    // UH_dynamic: the data will be repeatedly modified and
+    // re-rendered.  This is for data that will be modified at
+    // runtime, such as animated or soft-skinned vertices.
+    UH_dynamic,
+  };
+};
+
+#endif
+

+ 5 - 13
panda/src/gobj/qpgeomVertexArrayData.I

@@ -32,17 +32,9 @@ get_array_format() const {
 //       Access: Published
 //  Description: Returns the usage hint that describes to the
 //               rendering backend how often the vertex data will be
-//               modified and/or rendered.  This is provided as a
-//               performance optimization only, and does not
-//               constraing actual usage; although it may be an
-//               important optimization.
-//
-//               This may only be specified to the GeomVertexArrayData
-//               constructor.  If you need to change it, you must
-//               create a new GeomVertexArrayData object (but you can
-//               just assign the same data pointer to the new object).
+//               modified and/or rendered.  See GeomUsageHint.
 ////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexArrayData::UsageHint qpGeomVertexArrayData::
+INLINE qpGeomUsageHint::UsageHint qpGeomVertexArrayData::
 get_usage_hint() const {
   return _usage_hint;
 }
@@ -107,7 +99,7 @@ set_data(CPTA_uchar array) {
 ////////////////////////////////////////////////////////////////////
 INLINE int qpGeomVertexArrayData::
 get_num_vertices() const {
-  return get_num_bytes() / _array_format->get_stride();
+  return get_data_size_bytes() / _array_format->get_stride();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -122,12 +114,12 @@ clear_vertices() {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexArrayData::get_num_bytes
+//     Function: qpGeomVertexArrayData::get_data_size_bytes
 //       Access: Published
 //  Description: Returns the number of bytes stored in the array.
 ////////////////////////////////////////////////////////////////////
 INLINE int qpGeomVertexArrayData::
-get_num_bytes() const {
+get_data_size_bytes() const {
   CDReader cdata(_cycler);
   return cdata->_data.size();
 }

+ 16 - 16
panda/src/gobj/qpgeomVertexArrayData.cxx

@@ -41,7 +41,7 @@ qpGeomVertexArrayData() {
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexArrayData::
 qpGeomVertexArrayData(const qpGeomVertexArrayFormat *array_format,
-                      qpGeomVertexArrayData::UsageHint usage_hint) :
+                      qpGeomUsageHint::UsageHint usage_hint) :
   _array_format(array_format),
   _usage_hint(usage_hint)
 {
@@ -147,7 +147,7 @@ set_num_vertices(int n) {
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexArrayData::
 prepare(PreparedGraphicsObjects *prepared_objects) {
-  prepared_objects->enqueue_data(this);
+  prepared_objects->enqueue_vertex_buffer(this);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -155,7 +155,7 @@ prepare(PreparedGraphicsObjects *prepared_objects) {
 //       Access: Public
 //  Description: Creates a context for the data on the particular
 //               GSG, if it does not already exist.  Returns the new
-//               (or old) DataContext.  This assumes that the
+//               (or old) VertexBufferContext.  This assumes that the
 //               GraphicsStateGuardian is the currently active
 //               rendering context and that it is ready to accept new
 //               datas.  If this is not necessarily the case, you
@@ -166,7 +166,7 @@ prepare(PreparedGraphicsObjects *prepared_objects) {
 //               explicitly prepared by the user before it may be
 //               rendered.
 ////////////////////////////////////////////////////////////////////
-DataContext *qpGeomVertexArrayData::
+VertexBufferContext *qpGeomVertexArrayData::
 prepare_now(PreparedGraphicsObjects *prepared_objects, 
             GraphicsStateGuardianBase *gsg) {
   Contexts::const_iterator ci;
@@ -175,11 +175,11 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
     return (*ci).second;
   }
 
-  DataContext *dc = prepared_objects->prepare_data_now(this, gsg);
-  if (dc != (DataContext *)NULL) {
-    _contexts[prepared_objects] = dc;
+  VertexBufferContext *vbc = prepared_objects->prepare_vertex_buffer_now(this, gsg);
+  if (vbc != (VertexBufferContext *)NULL) {
+    _contexts[prepared_objects] = vbc;
   }
-  return dc;
+  return vbc;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -194,13 +194,13 @@ release(PreparedGraphicsObjects *prepared_objects) {
   Contexts::iterator ci;
   ci = _contexts.find(prepared_objects);
   if (ci != _contexts.end()) {
-    DataContext *dc = (*ci).second;
-    prepared_objects->release_data(dc);
+    VertexBufferContext *vbc = (*ci).second;
+    prepared_objects->release_vertex_buffer(vbc);
     return true;
   }
 
   // Maybe it wasn't prepared yet, but it's about to be.
-  return prepared_objects->dequeue_data(this);
+  return prepared_objects->dequeue_vertex_buffer(this);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -214,7 +214,7 @@ int qpGeomVertexArrayData::
 release_all() {
   // We have to traverse a copy of the _contexts list, because the
   // PreparedGraphicsObjects object will call clear_prepared() in response
-  // to each release_data(), and we don't want to be modifying the
+  // to each release_vertex_buffer(), and we don't want to be modifying the
   // _contexts list while we're traversing it.
   Contexts temp = _contexts;
   int num_freed = (int)_contexts.size();
@@ -222,11 +222,11 @@ release_all() {
   Contexts::const_iterator ci;
   for (ci = temp.begin(); ci != temp.end(); ++ci) {
     PreparedGraphicsObjects *prepared_objects = (*ci).first;
-    DataContext *dc = (*ci).second;
-    prepared_objects->release_data(dc);
+    VertexBufferContext *vbc = (*ci).second;
+    prepared_objects->release_vertex_buffer(vbc);
   }
 
-  // Now that we've called release_data() on every known context,
+  // Now that we've called release_vertex_buffer() on every known context,
   // the _contexts list should have completely emptied itself.
   nassertr(_contexts.empty(), num_freed);
 
@@ -240,7 +240,7 @@ release_all() {
 //               from the data array's table, without actually
 //               releasing the data array.  This is intended to be
 //               called only from
-//               PreparedGraphicsObjects::release_data(); it should
+//               PreparedGraphicsObjects::release_vertex_buffer(); it should
 //               never be called by user code.
 ////////////////////////////////////////////////////////////////////
 void qpGeomVertexArrayData::

+ 9 - 26
panda/src/gobj/qpgeomVertexArrayData.h

@@ -22,6 +22,7 @@
 #include "pandabase.h"
 #include "typedWritableReferenceCount.h"
 #include "qpgeomVertexArrayFormat.h"
+#include "qpgeomUsageHint.h"
 #include "pta_uchar.h"
 #include "updateSeq.h"
 #include "cycleData.h"
@@ -31,7 +32,7 @@
 #include "pmap.h"
 
 class PreparedGraphicsObjects;
-class DataContext;
+class VertexBufferContext;
 class GraphicsStateGuardianBase;
 
 ////////////////////////////////////////////////////////////////////
@@ -53,26 +54,8 @@ private:
   qpGeomVertexArrayData();
 
 PUBLISHED:
-  enum UsageHint {
-    // UH_client: don't attempt to upload the data as a "vertex
-    // buffer"; always keep it on the client.
-    UH_client,
-
-    // UH_stream: the data will be created once, used to render a few
-    // times, and then discarded.
-    UH_stream,
-
-    // UH_static: the data will be created once, and used to render
-    // many times, without modification.
-    UH_static,
-
-    // UH_dynamic: the data will be repeatedly modified and
-    // re-rendered.
-    UH_dynamic,
-  };
-
   qpGeomVertexArrayData(const qpGeomVertexArrayFormat *array_format,
-                        UsageHint usage_hint);
+                        qpGeomUsageHint::UsageHint usage_hint);
   qpGeomVertexArrayData(const qpGeomVertexArrayData &copy);
 private:
   void operator = (const qpGeomVertexArrayData &copy);
@@ -80,7 +63,7 @@ PUBLISHED:
   virtual ~qpGeomVertexArrayData();
 
   INLINE const qpGeomVertexArrayFormat *get_array_format() const;
-  INLINE UsageHint get_usage_hint() const;
+  INLINE qpGeomUsageHint::UsageHint get_usage_hint() const;
 
   INLINE CPTA_uchar get_data() const;
   INLINE PTA_uchar modify_data();
@@ -90,14 +73,14 @@ PUBLISHED:
   bool set_num_vertices(int n);
   INLINE void clear_vertices();
 
-  INLINE int get_num_bytes() const;
+  INLINE int get_data_size_bytes() const;
   INLINE UpdateSeq get_modified() const;
 
   void prepare(PreparedGraphicsObjects *prepared_objects);
 
 public:
-  DataContext *prepare_now(PreparedGraphicsObjects *prepared_objects, 
-                           GraphicsStateGuardianBase *gsg);
+  VertexBufferContext *prepare_now(PreparedGraphicsObjects *prepared_objects, 
+                                   GraphicsStateGuardianBase *gsg);
   bool release(PreparedGraphicsObjects *prepared_objects);
   int release_all();
 
@@ -105,14 +88,14 @@ private:
   void clear_prepared(PreparedGraphicsObjects *prepared_objects);
 
   CPT(qpGeomVertexArrayFormat) _array_format;
-  UsageHint _usage_hint;
+  qpGeomUsageHint::UsageHint _usage_hint;
 
   // A GeomVertexArrayData keeps a list (actually, a map) of all the
   // PreparedGraphicsObjects tables that it has been prepared into.
   // Each PGO conversely keeps a list (a set) of all the Geoms that
   // have been prepared there.  When either destructs, it removes
   // itself from the other's list.
-  typedef pmap<PreparedGraphicsObjects *, DataContext *> Contexts;
+  typedef pmap<PreparedGraphicsObjects *, VertexBufferContext *> Contexts;
   Contexts _contexts;
 
   // This is the data that must be cycled between pipeline stages.

+ 8 - 6
panda/src/gobj/qpgeomVertexData.I

@@ -33,14 +33,16 @@ get_format() const {
 //       Access: Published
 //  Description: Returns the usage hint that was passed to the
 //               constructor, and which will be passed to each array
-//               data object created initially.  However, each
-//               individual array may be replaced with a different
-//               array object with an independent usage hint
-//               specified.
+//               data object created initially, and arrays created as
+//               the result of a convert_to() operation.  See
+//               GeomUsageHint.
 //
-//               See GeomVertexArrayData::get_usage_hint().
+//               However, each individual array may be replaced with a
+//               different array object with an independent usage hint
+//               specified, so there is no guarantee that the
+//               individual arrays all have the same usage_hint.
 ////////////////////////////////////////////////////////////////////
-INLINE qpGeomVertexArrayData::UsageHint qpGeomVertexData::
+INLINE qpGeomUsageHint::UsageHint qpGeomVertexData::
 get_usage_hint() const {
   return _usage_hint;
 }

+ 4 - 4
panda/src/gobj/qpgeomVertexData.cxx

@@ -44,7 +44,7 @@ qpGeomVertexData() {
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexData::
 qpGeomVertexData(const qpGeomVertexFormat *format,
-                 qpGeomVertexArrayData::UsageHint usage_hint) :
+                 qpGeomUsageHint::UsageHint usage_hint) :
   _format(format),
   _usage_hint(usage_hint)
 {
@@ -132,7 +132,7 @@ get_num_vertices() const {
 
   // Look up the answer on the first array (since any array will do).
   int stride = _format->get_array(0)->get_stride();
-  return cdata->_arrays[0]->get_num_bytes() / stride;
+  return cdata->_arrays[0]->get_data_size_bytes() / stride;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -211,7 +211,7 @@ get_num_bytes() const {
 
   Arrays::const_iterator ai;
   for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) {
-    num_bytes += (*ai)->get_num_bytes();
+    num_bytes += (*ai)->get_data_size_bytes();
   }
 
   return num_bytes;
@@ -405,7 +405,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
 
   {
     CDReader cdata(_cycler);
-    int array_size = (int)cdata->_arrays[array]->get_num_bytes();
+    int array_size = (int)cdata->_arrays[array]->get_data_size_bytes();
     if (element + data_type->get_total_bytes() > array_size) {
       // Whoops, we need more vertices!
       CDWriter cdataw(_cycler, cdata);

+ 4 - 3
panda/src/gobj/qpgeomVertexData.h

@@ -24,6 +24,7 @@
 #include "qpgeomVertexFormat.h"
 #include "qpgeomVertexDataType.h"
 #include "qpgeomVertexArrayData.h"
+#include "qpgeomUsageHint.h"
 #include "internalName.h"
 #include "cycleData.h"
 #include "cycleDataReader.h"
@@ -63,13 +64,13 @@ private:
   qpGeomVertexData();
 PUBLISHED:
   qpGeomVertexData(const qpGeomVertexFormat *format, 
-                   qpGeomVertexArrayData::UsageHint usage_hint);
+                   qpGeomUsageHint::UsageHint usage_hint);
   qpGeomVertexData(const qpGeomVertexData &copy);
   void operator = (const qpGeomVertexData &copy);
   virtual ~qpGeomVertexData();
 
   INLINE const qpGeomVertexFormat *get_format() const;
-  INLINE qpGeomVertexArrayData::UsageHint get_usage_hint() const;
+  INLINE qpGeomUsageHint::UsageHint get_usage_hint() const;
 
   int get_num_vertices() const;
   INLINE bool set_num_vertices(int n);
@@ -113,7 +114,7 @@ private:
 
 private:
   CPT(qpGeomVertexFormat) _format;
-  qpGeomVertexArrayData::UsageHint _usage_hint;
+  qpGeomUsageHint::UsageHint _usage_hint;
 
   typedef pvector< PT(qpGeomVertexArrayData) > Arrays;
 

+ 91 - 0
panda/src/gobj/vertexBufferContext.I

@@ -0,0 +1,91 @@
+// Filename: vertexBufferContext.I
+// Created by:  drose (17Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE VertexBufferContext::
+VertexBufferContext(qpGeomVertexArrayData *data) :
+  _data(data),
+  // Initially, the number of bytes is zero, until the data has been
+  // loaded (and mark_loaded() is called).
+  _data_size_bytes(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::get_data
+//       Access: Public
+//  Description: Returns the pointer to the client-side array data
+//               object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexArrayData *VertexBufferContext::
+get_data() const {
+  return _data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::get_data_size_bytes
+//       Access: Public
+//  Description: Returns the number of bytes previously reported for
+//               the data object.  This is used to track changes in
+//               the data object's allocated size; if it changes from
+//               this, we need to create a new buffer.
+////////////////////////////////////////////////////////////////////
+INLINE int VertexBufferContext::
+get_data_size_bytes() const {
+  return _data_size_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::changed_size
+//       Access: Public
+//  Description: Returns true if the data has changed size since the
+//               last time mark_loaded() was called.
+////////////////////////////////////////////////////////////////////
+INLINE bool VertexBufferContext::
+changed_size() const {
+  return get_data_size_bytes() != _data->get_data_size_bytes();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::was_modified
+//       Access: Public
+//  Description: Returns true if the data has been modified since the
+//               last time mark_loaded() was called.
+////////////////////////////////////////////////////////////////////
+INLINE bool VertexBufferContext::
+was_modified() const {
+  return _modified != _data->get_modified();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VertexBufferContext::mark_loaded
+//       Access: Public
+//  Description: Should be called after the VertexBufferContext has been
+//               loaded into graphics memory, this updates the
+//               internal flags for changed_size() and modified().
+////////////////////////////////////////////////////////////////////
+INLINE void VertexBufferContext::
+mark_loaded() {
+  _data_size_bytes = _data->get_data_size_bytes();
+  _modified = _data->get_modified();
+}

+ 21 - 0
panda/src/gobj/vertexBufferContext.cxx

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

+ 11 - 11
panda/src/gobj/dataContext.h → panda/src/gobj/vertexBufferContext.h

@@ -1,4 +1,4 @@
-// Filename: dataContext.h
+// Filename: vertexBufferContext.h
 // Created by:  drose (17Mar05)
 //
 ////////////////////////////////////////////////////////////////////
@@ -16,8 +16,8 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#ifndef DATACONTEXT_H
-#define DATACONTEXT_H
+#ifndef VERTEXBUFFERCONTEXT_H
+#define VERTEXBUFFERCONTEXT_H
 
 #include "pandabase.h"
 
@@ -26,7 +26,7 @@
 #include "qpgeomVertexArrayData.h"
 
 ////////////////////////////////////////////////////////////////////
-//       Class : DataContext
+//       Class : VertexBufferContext
 // Description : This is a special class object that holds all the
 //               information returned by a particular GSG to indicate
 //               the vertex data array's internal context identifier.
@@ -36,13 +36,13 @@
 //               allocate a vertex buffer for the array.  OpenGL can
 //               create a buffer object.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA DataContext : public SavedContext {
+class EXPCL_PANDA VertexBufferContext : public SavedContext {
 public:
-  INLINE DataContext(qpGeomVertexArrayData *data);
+  INLINE VertexBufferContext(qpGeomVertexArrayData *data);
 
   INLINE qpGeomVertexArrayData *get_data() const;
 
-  INLINE int get_num_bytes() const;
+  INLINE int get_data_size_bytes() const;
   INLINE bool changed_size() const;
   INLINE bool was_modified() const;
 
@@ -50,11 +50,11 @@ public:
 
 private:
   // This cannot be a PT(qpGeomVertexArrayData), because the data and
-  // the GSG both own their DataContexts!  That would create a
+  // the GSG both own their VertexBufferContexts!  That would create a
   // circular reference count.
   qpGeomVertexArrayData *_data;
   UpdateSeq _modified;
-  int _num_bytes;
+  int _data_size_bytes;
 
 public:
   static TypeHandle get_class_type() {
@@ -62,7 +62,7 @@ public:
   }
   static void init_type() {
     SavedContext::init_type();
-    register_type(_type_handle, "DataContext",
+    register_type(_type_handle, "VertexBufferContext",
                   SavedContext::get_class_type());
   }
   virtual TypeHandle get_type() const {
@@ -76,7 +76,7 @@ private:
   friend class PreparedGraphicsObjects;
 };
 
-#include "dataContext.I"
+#include "vertexBufferContext.I"
 
 #endif
 

+ 8 - 3
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -30,7 +30,8 @@ class RenderBuffer;
 class GraphicsWindow;
 class NodePath;
 
-class DataContext;
+class VertexBufferContext;
+class IndexBufferContext;
 class GeomContext;
 class GeomNode;
 class Geom;
@@ -46,6 +47,7 @@ class GeomTrifan;
 class GeomSphere;
 class qpGeomVertexData;
 class qpGeomVertexArrayData;
+class qpGeomPrimitive;
 class qpGeomTriangles;
 class qpGeomTristrips;
 class qpGeomTrifans;
@@ -134,8 +136,11 @@ public:
   virtual GeomContext *prepare_geom(Geom *geom)=0;
   virtual void release_geom(GeomContext *gc)=0;
 
-  virtual DataContext *prepare_data(qpGeomVertexArrayData *data)=0;
-  virtual void release_data(DataContext *gc)=0;
+  virtual VertexBufferContext *prepare_vertex_buffer(qpGeomVertexArrayData *data)=0;
+  virtual void release_vertex_buffer(VertexBufferContext *vbc)=0;
+
+  virtual IndexBufferContext *prepare_index_buffer(qpGeomPrimitive *data)=0;
+  virtual void release_index_buffer(IndexBufferContext *ibc)=0;
 
   virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state)=0;
 

+ 2 - 1
panda/src/pstatclient/pStatProperties.cxx

@@ -153,7 +153,8 @@ static LevelCollectorProperties level_properties[] = {
   { 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, "Vertex buffers:Active",            { 1.0, 0.0, 0.5 } },
+  { 1, "Vertex buffers:Active vertex",     { 1.0, 0.0, 0.5 } },
+  { 1, "Vertex buffers:Active index" ,     { 0.5, 0.6, 1.0 } },
   { 1, "Vertex buffers",                   { 0.0, 0.0, 1.0 },  "MB", 12, 1048576 },
   { 1, "Vertices",                         { 0.5, 0.2, 0.0 },  "K", 10, 1000 },
   { 1, "Vertices:Other",                   { 0.2, 0.2, 0.2 } },