David Rose преди 20 години
родител
ревизия
4f47bf53e7
променени са 33 файла, в които са добавени 1068 реда и са изтрити 421 реда
  1. 60 20
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  2. 2 0
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  3. 5 2
      panda/src/dxgsg8/dxIndexBufferContext8.cxx
  4. 61 19
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  5. 2 1
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  6. 94 14
      panda/src/gobj/internalName.I
  7. 1 0
      panda/src/gobj/internalName.cxx
  8. 2 0
      panda/src/gobj/internalName.h
  9. 3 0
      panda/src/gobj/qpgeomEnums.cxx
  10. 1 0
      panda/src/gobj/qpgeomEnums.h
  11. 14 8
      panda/src/gobj/qpgeomLines.cxx
  12. 1 1
      panda/src/gobj/qpgeomLines.h
  13. 18 14
      panda/src/gobj/qpgeomLinestrips.cxx
  14. 1 1
      panda/src/gobj/qpgeomLinestrips.h
  15. 43 48
      panda/src/gobj/qpgeomPrimitive.I
  16. 208 119
      panda/src/gobj/qpgeomPrimitive.cxx
  17. 26 15
      panda/src/gobj/qpgeomPrimitive.h
  18. 22 13
      panda/src/gobj/qpgeomTriangles.cxx
  19. 1 1
      panda/src/gobj/qpgeomTriangles.h
  20. 16 13
      panda/src/gobj/qpgeomTrifans.cxx
  21. 1 1
      panda/src/gobj/qpgeomTrifans.h
  22. 52 42
      panda/src/gobj/qpgeomTristrips.cxx
  23. 3 2
      panda/src/gobj/qpgeomTristrips.h
  24. 4 0
      panda/src/gobj/qpgeomVertexColumn.cxx
  25. 75 33
      panda/src/gobj/qpgeomVertexReader.I
  26. 101 3
      panda/src/gobj/qpgeomVertexReader.cxx
  27. 7 0
      panda/src/gobj/qpgeomVertexReader.h
  28. 40 0
      panda/src/gobj/qpgeomVertexRewriter.I
  29. 4 0
      panda/src/gobj/qpgeomVertexRewriter.h
  30. 78 38
      panda/src/gobj/qpgeomVertexWriter.I
  31. 106 4
      panda/src/gobj/qpgeomVertexWriter.cxx
  32. 7 0
      panda/src/gobj/qpgeomVertexWriter.h
  33. 9 9
      panda/src/pgraph/cullableObject.cxx

+ 60 - 20
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -55,6 +55,7 @@
 #include "qpgeomTristrips.h"
 #include "qpgeomTrifans.h"
 #include "qpgeomLines.h"
+#include "qpGeomVertexReader.h"
 #include "dxGeomMunger8.h"
 #include "config_gobj.h"
 #include "dxVertexBufferContext8.h"
@@ -2747,13 +2748,15 @@ draw_triangles(const qpGeomTriangles *primitive) {
        0, primitive->get_num_primitives());
 
   } else {
+    D3DFORMAT index_type = get_index_type(primitive->get_index_type());
+
     _pD3DDevice->DrawIndexedPrimitiveUP
       (D3DPT_TRIANGLELIST, 
        primitive->get_min_vertex(),
        primitive->get_max_vertex() - primitive->get_min_vertex() + 1,
        primitive->get_num_primitives(), 
        primitive->get_vertices(),
-       D3DFMT_INDEX16,
+       index_type,
        _vertex_data->get_array(0)->get_data(),
        _vertex_data->get_format()->get_array(0)->get_stride());
   }
@@ -2768,6 +2771,7 @@ void DXGraphicsStateGuardian8::
 draw_tristrips(const qpGeomTristrips *primitive) {
   int min_vertex = primitive->get_min_vertex();
   int max_vertex = primitive->get_max_vertex();
+  D3DFORMAT index_type = get_index_type(primitive->get_index_type());
 
   if (connect_triangle_strips && _current_fill_mode != RenderModeAttrib::M_wireframe) {
     // One long triangle strip, connected by the degenerate vertices
@@ -2788,7 +2792,7 @@ draw_tristrips(const qpGeomTristrips *primitive) {
         (D3DPT_TRIANGLESTRIP, 
          min_vertex, max_vertex - min_vertex + 1,
          primitive->get_num_vertices() - 2, 
-         primitive->get_vertices(), D3DFMT_INDEX16,
+         primitive->get_data(), index_type,
          _vertex_data->get_array(0)->get_data(),
          _vertex_data->get_format()->get_array(0)->get_stride());
     }
@@ -2797,9 +2801,11 @@ draw_tristrips(const qpGeomTristrips *primitive) {
     // Send the individual triangle strips, stepping over the
     // degenerate vertices.
     CPTA_int ends = primitive->get_ends();
-    CPTA_ushort mins = primitive->get_mins();
-    CPTA_ushort maxs = primitive->get_maxs();
-    nassertv(mins.size() == ends.size() && maxs.size() == ends.size());
+    int index_stride = primitive->get_index_stride();
+
+    qpGeomVertexReader mins(primitive->get_mins(), 0);
+    qpGeomVertexReader maxs(primitive->get_mins(), 0);
+    nassertv(mins.get_num_vertices() == ends.size() && maxs.get_num_vertices() == ends.size());
     
     if (_vbuffer_active) {
       IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this);
@@ -2809,10 +2815,12 @@ draw_tristrips(const qpGeomTristrips *primitive) {
       unsigned int start = 0;
       for (size_t i = 0; i < ends.size(); i++) {
         _vertices_tristrip_pcollector.add_level(ends[i] - start);
+        unsigned int min = mins.get_data1i();
+        unsigned int max = maxs.get_data1i();
         _pD3DDevice->DrawIndexedPrimitive
           (D3DPT_TRIANGLESTRIP,
-           mins[i], maxs[i] - mins[i] + 1, 
-           start, ends[i] - start - 2);
+           min, max - min + 1, 
+           start * index_stride, ends[i] - start - 2);
         
         start = ends[i] + 2;
       }
@@ -2820,16 +2828,18 @@ draw_tristrips(const qpGeomTristrips *primitive) {
     } else {
       CPTA_uchar array_data = _vertex_data->get_array(0)->get_data();
       int stride = _vertex_data->get_format()->get_array(0)->get_stride();
-      CPTA_ushort vertices = primitive->get_vertices();
+      CPTA_uchar vertices = primitive->get_data();
       
       unsigned int start = 0;
       for (size_t i = 0; i < ends.size(); i++) {
         _vertices_tristrip_pcollector.add_level(ends[i] - start);
+        unsigned int min = mins.get_data1i();
+        unsigned int max = maxs.get_data1i();
         _pD3DDevice->DrawIndexedPrimitiveUP
           (D3DPT_TRIANGLESTRIP, 
-           mins[i], maxs[i] - mins[i] + 1, 
+           min, max - min + 1, 
            ends[i] - start - 2,
-           vertices + start, D3DFMT_INDEX16,
+           vertices + start * index_stride, index_type,
            array_data, stride);
         
         start = ends[i] + 2;
@@ -2847,13 +2857,16 @@ void DXGraphicsStateGuardian8::
 draw_trifans(const qpGeomTrifans *primitive) {
   int min_vertex = primitive->get_min_vertex();
   int max_vertex = primitive->get_max_vertex();
+  D3DFORMAT index_type = get_index_type(primitive->get_index_type());
 
   // Send the individual triangle fans.  There's no connecting fans
   // with degenerate vertices, so no worries about that.
   CPTA_int ends = primitive->get_ends();
-  CPTA_ushort mins = primitive->get_mins();
-  CPTA_ushort maxs = primitive->get_maxs();
-  nassertv(mins.size() == ends.size() && maxs.size() == ends.size());
+  int index_stride = primitive->get_index_stride();
+
+  qpGeomVertexReader mins(primitive->get_mins(), 0);
+  qpGeomVertexReader maxs(primitive->get_mins(), 0);
+  nassertv(mins.get_num_vertices() == ends.size() && maxs.get_num_vertices() == ends.size());
   
   if (_vbuffer_active) {
     IndexBufferContext *ibc = ((qpGeomPrimitive *)primitive)->prepare_now(get_prepared_objects(), this);
@@ -2863,10 +2876,12 @@ draw_trifans(const qpGeomTrifans *primitive) {
     unsigned int start = 0;
     for (size_t i = 0; i < ends.size(); i++) {
       _vertices_trifan_pcollector.add_level(ends[i] - start);
+      unsigned int min = mins.get_data1i();
+      unsigned int max = maxs.get_data1i();
       _pD3DDevice->DrawIndexedPrimitive
         (D3DPT_TRIANGLEFAN,
-         mins[i], maxs[i] - mins[i] + 1, 
-         start, ends[i] - start - 2);
+         min, max - min + 1,
+         start * index_stride, ends[i] - start - 2);
       
       start = ends[i] + 2;
     }
@@ -2874,16 +2889,18 @@ draw_trifans(const qpGeomTrifans *primitive) {
   } else {
     CPTA_uchar array_data = _vertex_data->get_array(0)->get_data();
     int stride = _vertex_data->get_format()->get_array(0)->get_stride();
-    CPTA_ushort vertices = primitive->get_vertices();
+    CPTA_uchar vertices = primitive->get_data();
     
     unsigned int start = 0;
     for (size_t i = 0; i < ends.size(); i++) {
       _vertices_trifan_pcollector.add_level(ends[i] - start);
+      unsigned int min = mins.get_data1i();
+      unsigned int max = maxs.get_data1i();
       _pD3DDevice->DrawIndexedPrimitiveUP
         (D3DPT_TRIANGLEFAN, 
-         mins[i], maxs[i] - mins[i] + 1, 
+         min, max - min + 1, 
          ends[i] - start - 2,
-         vertices + start, D3DFMT_INDEX16,
+         vertices + start * index_stride, index_type,
          array_data, stride);
       
       start = ends[i] + 2;
@@ -2911,13 +2928,15 @@ draw_lines(const qpGeomLines *primitive) {
        0, primitive->get_num_primitives());
 
   } else {
+    D3DFORMAT index_type = get_index_type(primitive->get_index_type());
+
     _pD3DDevice->DrawIndexedPrimitiveUP
       (D3DPT_LINELIST, 
        primitive->get_min_vertex(),
        primitive->get_max_vertex() - primitive->get_min_vertex() + 1,
        primitive->get_num_primitives(), 
-       primitive->get_vertices(),
-       D3DFMT_INDEX16,
+       primitive->get_data(),
+       index_type,
        _vertex_data->get_array(0)->get_data(),
        _vertex_data->get_format()->get_array(0)->get_stride());
   }
@@ -4249,6 +4268,27 @@ end_frame() {
   GraphicsStateGuardian::end_frame();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::get_index_type
+//       Access: Protected, Static
+//  Description: Maps from the Geom's internal numeric type symbols
+//               to DirectX's.
+////////////////////////////////////////////////////////////////////
+D3DFORMAT DXGraphicsStateGuardian8::
+get_index_type(qpGeom::NumericType numeric_type) {
+  switch (numeric_type) {
+  case qpGeom::NT_uint16:
+    return D3DFMT_INDEX16;
+
+  case qpGeom::NT_uint32:
+    return D3DFMT_INDEX32;
+  }
+
+  dxgsg8_cat.error()
+    << "Invalid index NumericType value (" << (int)numeric_type << ")\n";
+  return D3DFMT_INDEX16;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::set_draw_buffer
 //       Access: Protected

+ 2 - 0
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -152,6 +152,8 @@ public:
   INLINE float compute_distance_to(const LPoint3f &point) const;
   virtual void set_color_clear_value(const Colorf& value);
 
+  static D3DFORMAT get_index_type(qpGeom::NumericType numeric_type);
+
 public:
   // recreate_tex_callback needs these to be public
   DXScreenData *_pScrn;

+ 5 - 2
panda/src/dxgsg8/dxIndexBufferContext8.cxx

@@ -65,9 +65,12 @@ create_ibuffer(DXScreenData &scrn) {
     _ibuffer = NULL;
   }
 
+  D3DFORMAT index_type = 
+    DXGraphicsStateGuardian8::get_index_type(get_data()->get_index_type());
+
   HRESULT hr = scrn.pD3DDevice->CreateIndexBuffer
     (get_data()->get_data_size_bytes(), D3DUSAGE_WRITEONLY,
-     D3DFMT_INDEX16, D3DPOOL_MANAGED, &_ibuffer);
+     index_type, D3DPOOL_MANAGED, &_ibuffer);
   if (FAILED(hr)) {
     dxgsg8_cat.warning()
       << "CreateIndexBuffer failed" << D3DERRORSTRING(hr);
@@ -104,7 +107,7 @@ upload_data() {
     return;
   }
 
-  memcpy(local_pointer, get_data()->get_vertices(), data_size);
+  memcpy(local_pointer, get_data()->get_data(), data_size);
 
   _ibuffer->Unlock();
 }

+ 61 - 19
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2480,13 +2480,14 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
 void CLP(GraphicsStateGuardian)::
 draw_triangles(const qpGeomTriangles *primitive) {
   _vertices_tri_pcollector.add_level(primitive->get_num_vertices());
-  const unsigned short *client_pointer = setup_primitive(primitive);
+  const unsigned char *client_pointer = setup_primitive(primitive);
 
   _glDrawRangeElements(GL_TRIANGLES, 
                        primitive->get_min_vertex(),
                        primitive->get_max_vertex(),
                        primitive->get_num_vertices(),
-                       GL_UNSIGNED_SHORT, client_pointer);
+                       get_numeric_type(primitive->get_index_type()), 
+                       client_pointer);
 
   report_my_gl_errors();
 }
@@ -2498,7 +2499,7 @@ draw_triangles(const qpGeomTriangles *primitive) {
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 draw_tristrips(const qpGeomTristrips *primitive) {
-  const unsigned short *client_pointer = setup_primitive(primitive);
+  const unsigned char *client_pointer = setup_primitive(primitive);
 
   if (connect_triangle_strips && _render_mode != RenderModeAttrib::M_wireframe) {
     // One long triangle strip, connected by the degenerate vertices
@@ -2508,22 +2509,27 @@ draw_tristrips(const qpGeomTristrips *primitive) {
                          primitive->get_min_vertex(),
                          primitive->get_max_vertex(),
                          primitive->get_num_vertices(),
-                         GL_UNSIGNED_SHORT, client_pointer);
+                         get_numeric_type(primitive->get_index_type()), 
+                         client_pointer);
 
   } else {
     // Send the individual triangle strips, stepping over the
     // degenerate vertices.
     CPTA_int ends = primitive->get_ends();
-    CPTA_ushort mins = primitive->get_mins();
-    CPTA_ushort maxs = primitive->get_maxs();
-    nassertv(mins.size() == ends.size() && maxs.size() == ends.size());
+    int index_stride = primitive->get_index_stride();
+
+    qpGeomVertexReader mins(primitive->get_mins(), 0);
+    qpGeomVertexReader maxs(primitive->get_mins(), 0);
+    nassertv(mins.get_num_vertices() == ends.size() && maxs.get_num_vertices() == ends.size());
     
     unsigned int start = 0;
     for (size_t i = 0; i < ends.size(); i++) {
       _vertices_tristrip_pcollector.add_level(ends[i] - start);
       _glDrawRangeElements(GL_TRIANGLE_STRIP, 
-                           mins[i], maxs[i], ends[i] - start,
-                           GL_UNSIGNED_SHORT, client_pointer + start);
+                           mins.get_data1i(), maxs.get_data1i(), 
+                           ends[i] - start,
+                           get_numeric_type(primitive->get_index_type()), 
+                           client_pointer + start * index_stride);
       start = ends[i] + 2;
     }
   }
@@ -2531,6 +2537,37 @@ draw_tristrips(const qpGeomTristrips *primitive) {
   report_my_gl_errors();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::draw_trifans
+//       Access: Public, Virtual
+//  Description: Draws a series of triangle fans.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+draw_trifans(const qpGeomTrifans *primitive) {
+  const unsigned char *client_pointer = setup_primitive(primitive);
+
+  // Send the individual triangle fans.  There's no connecting fans
+  // with degenerate vertices, so no worries about that.
+  CPTA_int ends = primitive->get_ends();
+  int index_stride = primitive->get_index_stride();
+
+  qpGeomVertexReader mins(primitive->get_mins(), 0);
+  qpGeomVertexReader maxs(primitive->get_mins(), 0);
+  nassertv(mins.get_num_vertices() == ends.size() && maxs.get_num_vertices() == ends.size());
+
+  unsigned int start = 0;
+  for (size_t i = 0; i < ends.size(); i++) {
+    _vertices_trifan_pcollector.add_level(ends[i] - start);
+    _glDrawRangeElements(GL_TRIANGLE_FAN, 
+                         mins.get_data1i(), maxs.get_data1i(), ends[i] - start,
+                         get_numeric_type(primitive->get_index_type()), 
+                         client_pointer + start * index_stride);
+    start = ends[i] + 2;
+  }
+    
+  report_my_gl_errors();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::draw_lines
 //       Access: Public, Virtual
@@ -2539,13 +2576,14 @@ draw_tristrips(const qpGeomTristrips *primitive) {
 void CLP(GraphicsStateGuardian)::
 draw_lines(const qpGeomLines *primitive) {
   _vertices_other_pcollector.add_level(primitive->get_num_vertices());
-  const unsigned short *client_pointer = setup_primitive(primitive);
+  const unsigned char *client_pointer = setup_primitive(primitive);
 
   _glDrawRangeElements(GL_LINES, 
                        primitive->get_min_vertex(),
                        primitive->get_max_vertex(),
                        primitive->get_num_vertices(),
-                       GL_UNSIGNED_SHORT, client_pointer);
+                       get_numeric_type(primitive->get_index_type()), 
+                       client_pointer);
 
   report_my_gl_errors();
 }
@@ -2567,13 +2605,14 @@ draw_linestrips(const qpGeomLinestrips *primitive) {
 void CLP(GraphicsStateGuardian)::
 draw_points(const qpGeomPoints *primitive) {
   _vertices_other_pcollector.add_level(primitive->get_num_vertices());
-  const unsigned short *client_pointer = setup_primitive(primitive);
+  const unsigned char *client_pointer = setup_primitive(primitive);
 
   _glDrawRangeElements(GL_POINTS, 
                        primitive->get_min_vertex(),
                        primitive->get_max_vertex(),
                        primitive->get_num_vertices(),
-                       GL_UNSIGNED_SHORT, client_pointer);
+                       get_numeric_type(primitive->get_index_type()), 
+                       client_pointer);
 
   report_my_gl_errors();
 }
@@ -3005,12 +3044,12 @@ apply_index_buffer(IndexBufferContext *ibc) {
     }
     if (gibc->changed_size()) {
       _glBufferData(GL_ELEMENT_ARRAY_BUFFER, gibc->get_data()->get_data_size_bytes(),
-                    gibc->get_data()->get_vertices(), 
+                    gibc->get_data()->get_data(), 
                     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->get_data()->get_data());
     }
 
     gibc->mark_loaded();
@@ -3059,23 +3098,23 @@ release_index_buffer(IndexBufferContext *ibc) {
 //               this function returns the pointer to the data array
 //               in client memory, that is, the data array passed in.
 ////////////////////////////////////////////////////////////////////
-const unsigned short *CLP(GraphicsStateGuardian)::
+const unsigned char *CLP(GraphicsStateGuardian)::
 setup_primitive(const qpGeomPrimitive *data) {
   if (!_supports_buffers) {
     // No support for buffer objects; always render from client.
-    return data->get_vertices();
+    return data->get_data();
   }
   if (!vertex_buffers || _geom_display_list != 0 ||
       data->get_usage_hint() == qpGeom::UH_client) {
     // The array specifies client rendering only, or buffer objects
     // are configured off.
     _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
-    return data->get_vertices();
+    return data->get_data();
   }
 
   // Prepare the buffer object and bind it.
   IndexBufferContext *ibc = ((qpGeomPrimitive *)data)->prepare_now(get_prepared_objects(), this);
-  nassertr(ibc != (IndexBufferContext *)NULL, data->get_vertices());
+  nassertr(ibc != (IndexBufferContext *)NULL, data->get_data());
   apply_index_buffer(ibc);
 
   // NULL is the OpenGL convention for the first byte of the buffer object.
@@ -4735,6 +4774,9 @@ get_numeric_type(qpGeom::NumericType numeric_type) {
   case qpGeom::NT_uint16:
     return GL_UNSIGNED_SHORT;
 
+  case qpGeom::NT_uint32:
+    return GL_UNSIGNED_INT;
+
   case qpGeom::NT_uint8:
   case qpGeom::NT_packed_dcba:
   case qpGeom::NT_packed_dabc:

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

@@ -99,6 +99,7 @@ public:
                                      const qpGeomVertexData *vertex_data);
   virtual void draw_triangles(const qpGeomTriangles *primitive);
   virtual void draw_tristrips(const qpGeomTristrips *primitive);
+  virtual void draw_trifans(const qpGeomTrifans *primitive);
   virtual void draw_lines(const qpGeomLines *primitive);
   virtual void draw_linestrips(const qpGeomLinestrips *primitive);
   virtual void draw_points(const qpGeomPoints *primitive);
@@ -122,7 +123,7 @@ public:
   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);
+  const unsigned char *setup_primitive(const qpGeomPrimitive *data);
 
   virtual CPT(qpGeomMunger) get_geom_munger(const RenderState *state);
 

+ 94 - 14
panda/src/gobj/internalName.I

@@ -91,7 +91,9 @@ get_error() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_vertex
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "vertex".
+//  Description: Returns the standard InternalName "vertex".  This is
+//               the column header for the 3-d or 4-d vertex position
+//               information for each vertex.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_vertex() {
@@ -104,7 +106,9 @@ get_vertex() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_normal
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "normal".
+//  Description: Returns the standard InternalName "normal".  This is
+//               the column header for the 3-d lighting normal for
+//               each vertex.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_normal() {
@@ -117,7 +121,12 @@ get_normal() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_tangent
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "tangent".
+//  Description: Returns the standard InternalName "tangent".  This is
+//               the column header for the tangent vector associated
+//               with each vertex, which is a unit vector
+//               usually perpendicular to the normal and in the
+//               direction of the U texture coordinate change.  It is
+//               used for deriving bump maps.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_tangent() {
@@ -130,7 +139,13 @@ get_tangent() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_binormal
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "binormal".
+//  Description: Returns the standard InternalName "binormal".  This is
+//               the column header for the tangent vector associated
+//               with each vertex, which is a unit vector
+//               usually perpendicular to both the normal and the
+//               tangent, and in the direction of the V texture
+//               coordinate change.  It is used for deriving bump
+//               maps.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_binormal() {
@@ -143,7 +158,11 @@ get_binormal() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_texcoord
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "texcoord".
+//  Description: Returns the standard InternalName "texcoord".  This
+//               is the column header for the default texture
+//               coordinate set for each vertex.  It is also used for
+//               identifying the default texture coordinate set in a
+//               TextureStage.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_texcoord() {
@@ -157,8 +176,10 @@ get_texcoord() {
 //     Function: InternalName::get_texcoord_name
 //       Access: Published, Static
 //  Description: Returns the InternalName "texcoord.name", where name
-//               is the supplied string.  This, by convention,
-//               represents the named texture coordinate set.
+//               is the supplied string.  This is the column header
+//               for the named texture coordinate set for each vertex.
+//               It is also used for identifying the named texture
+//               coordinate set in a TextureStage.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_texcoord_name(const string &name) {
@@ -168,7 +189,9 @@ get_texcoord_name(const string &name) {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_color
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "color".
+//  Description: Returns the standard InternalName "color".  This is
+//               the column header for the 4-component color value for
+//               each vertex.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_color() {
@@ -181,7 +204,11 @@ get_color() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_rotate
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "rotate".
+//  Description: Returns the standard InternalName "rotate".  This is
+//               the column header for the floating-point rotate
+//               value, which represents a number of degrees
+//               counter-clockwise to rotate each point or point
+//               sprite.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_rotate() {
@@ -194,7 +221,11 @@ get_rotate() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_size
 //       Access: Published, Static
-//  Description: Returns the standard InternalName "size".
+//  Description: Returns the standard InternalName "size".  This is
+//               the column header for the floating-point size value,
+//               which overrides the thickness parameter of the
+//               RenderModeAttrib on a per-vertex (e.g. per-point)
+//               basis.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_size() {
@@ -208,6 +239,10 @@ get_size() {
 //     Function: InternalName::get_aspect_ratio
 //       Access: Published, Static
 //  Description: Returns the standard InternalName "aspect_ratio".
+//               This is the column header for the floating-point
+//               aspect ratio value, which is used to define
+//               non-square points.  This number is the ratio x / y,
+//               where y is the point size (above).
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_aspect_ratio() {
@@ -221,6 +256,10 @@ get_aspect_ratio() {
 //     Function: InternalName::get_transform_blend
 //       Access: Published, Static
 //  Description: Returns the standard InternalName "transform_blend".
+//               This is the column header for the integer
+//               transform_blend index, which is used to define vertex
+//               animation on the CPU by indexing to a particular
+//               vertex weighting from the TransformBlendPalette.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_transform_blend() {
@@ -234,6 +273,14 @@ get_transform_blend() {
 //     Function: InternalName::get_transform_weight
 //       Access: Published, Static
 //  Description: Returns the standard InternalName "transform_weight".
+//               This is the column header for the n-component
+//               transform_weight value, which is used in conjuntion
+//               with "transform_index" to define vertex animation on
+//               the graphics card.  The transform_weight value
+//               specifies the weight of the nth transform.  By
+//               convention, there are 1 fewer weight values than
+//               transforms, since the weights are assumed to sum to 1
+//               (and the last value is therefore implicit).
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_transform_weight() {
@@ -247,6 +294,14 @@ get_transform_weight() {
 //     Function: InternalName::get_transform_index
 //       Access: Published, Static
 //  Description: Returns the standard InternalName "transform_index".
+//               This is the column header for the n-component
+//               transform_index value, which is used in conjuntion
+//               with "transform_weight" to define vertex animation on
+//               the graphics card.  The transform_index value
+//               specifies the nth transform, by lookup in the
+//               TransformPalette.  The transform_index column may be
+//               omitted, in which case the nth transform is the nth
+//               entry in the palette.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_transform_index() {
@@ -259,16 +314,41 @@ get_transform_index() {
 ////////////////////////////////////////////////////////////////////
 //     Function: InternalName::get_morph
 //       Access: Published, Static
-//  Description: Returns an InternalName suitable for defining the
-//               morph deltas in the GeomVertexData to apply to the
-//               indicated data type name, using the named slider.
+//  Description: Returns an InternalName derived from the given base
+//               column name and the given slider name, which is the
+//               column header for the offset vector that should be
+//               applied to the base column name when the named morph
+//               slider is engaged.
+//
+//               Each morph slider requires a set of n morph columns,
+//               one for each base column it applies to.
 ////////////////////////////////////////////////////////////////////
 INLINE PT(InternalName) InternalName::
 get_morph(InternalName *column, const string &slider) {
-  // Returns column.morph.slider
+  // This actually returns "column.morph.slider", although that's just
+  // an implementation detail--as long as it returns a consistent,
+  // unique name for each combination of column and slider, everything
+  // is good.
   return column->append("morph")->append(slider);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_index
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "index".  This is
+//               the column header for the integer vertex index.  It
+//               is not used in the vertex data itself, but is used in
+//               the GeomPrimitive structure to index into the vertex
+//               data.
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_index() {
+  if (_index == (InternalName *)NULL) {
+    _index = InternalName::make("index");
+  }
+  return _index;
+}
+
 INLINE ostream &
 operator << (ostream &out, const InternalName &tcn) {
   tcn.output(out);

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

@@ -38,6 +38,7 @@ PT(InternalName) InternalName::_aspect_ratio;
 PT(InternalName) InternalName::_transform_blend;
 PT(InternalName) InternalName::_transform_weight;
 PT(InternalName) InternalName::_transform_index;
+PT(InternalName) InternalName::_index;
 
 TypeHandle InternalName::_type_handle;
 TypeHandle InternalName::_texcoord_type_handle;

+ 2 - 0
panda/src/gobj/internalName.h

@@ -78,6 +78,7 @@ PUBLISHED:
   INLINE static PT(InternalName) get_transform_weight();
   INLINE static PT(InternalName) get_transform_index();
   INLINE static PT(InternalName) get_morph(InternalName *column, const string &slider);
+  INLINE static PT(InternalName) get_index();
 
 private:
   PT(InternalName) _parent;
@@ -101,6 +102,7 @@ private:
   static PT(InternalName) _transform_blend;
   static PT(InternalName) _transform_weight;
   static PT(InternalName) _transform_index;
+  static PT(InternalName) _index;
   
 public:
   // Datagram stuff

+ 3 - 0
panda/src/gobj/qpgeomEnums.cxx

@@ -28,6 +28,9 @@ operator << (ostream &out, qpGeomEnums::NumericType numeric_type) {
   case qpGeomEnums::NT_uint16:
     return out << "uint16";
     
+  case qpGeomEnums::NT_uint32:
+    return out << "uint32";
+    
   case qpGeomEnums::NT_packed_dcba:
     return out << "packed_dcba";
     

+ 1 - 0
panda/src/gobj/qpgeomEnums.h

@@ -169,6 +169,7 @@ PUBLISHED:
   enum NumericType {
     NT_uint8,        // An integer 0..255
     NT_uint16,       // An integer 0..65535
+    NT_uint32,       // An integer 0..4294967296
     NT_packed_dcba,  // DirectX style, four byte values packed in a uint32
     NT_packed_dabc,  // DirectX packed color order (ARGB)
     NT_float32,      // A floating-point number

+ 14 - 8
panda/src/gobj/qpgeomLines.cxx

@@ -121,20 +121,26 @@ draw(GraphicsStateGuardianBase *gsg) const {
 //       Access: Protected, Virtual
 //  Description: The virtual implementation of do_rotate().
 ////////////////////////////////////////////////////////////////////
-CPTA_ushort qpGeomLines::
+CPT(qpGeomVertexArrayData) qpGeomLines::
 rotate_impl() const {
   // To rotate lines, we just move reverse the pairs of vertices.
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
 
-  PTA_ushort new_vertices;
-  new_vertices.reserve(vertices.size());
+  PT(qpGeomVertexArrayData) new_vertices = 
+    new qpGeomVertexArrayData(*vertices);
+  qpGeomVertexReader from(vertices, 0);
+  qpGeomVertexWriter to(new_vertices, 0);
 
-  for (int begin = 0; begin < (int)vertices.size(); begin += 2) {
-    new_vertices.push_back(vertices[begin + 1]);
-    new_vertices.push_back(vertices[begin]);
+  int num_vertices = vertices->get_num_vertices();
+
+  for (int begin = 0; begin < num_vertices; begin += 2) {
+    from.set_vertex(begin + 1);
+    to.set_data1i(from.get_data1i());
+    from.set_vertex(begin);
+    to.set_data1i(from.get_data1i());
   }
   
-  nassertr(new_vertices.size() == vertices.size(), CPTA_ushort());
+  nassertr(to.is_at_end(), NULL);
   return new_vertices;
 }
 

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

@@ -45,7 +45,7 @@ public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;
 
 protected:
-  virtual CPTA_ushort rotate_impl() const;
+  virtual CPT(qpGeomVertexArrayData) rotate_impl() const;
 
 public:
   static void register_with_read_factory();

+ 18 - 14
panda/src/gobj/qpgeomLinestrips.cxx

@@ -18,6 +18,7 @@
 
 #include "qpgeomLinestrips.h"
 #include "qpgeomLines.h"
+#include "qpgeomVertexRewriter.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -131,7 +132,8 @@ CPT(qpGeomPrimitive) qpGeomLinestrips::
 decompose_impl() const {
   PT(qpGeomLines) lines = new qpGeomLines(get_usage_hint());
   lines->set_shade_model(get_shade_model());
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
+  qpGeomVertexReader index(vertices, 0);
   CPTA_int ends = get_ends();
 
   int vi = 0;
@@ -139,20 +141,19 @@ decompose_impl() const {
   while (li < (int)ends.size()) {
     int end = ends[li];
     nassertr(vi + 1 <= end, lines.p());
-    nassertr(vi < (int)vertices.size(), this);
-    int v0 = vertices[vi];
+    int v0 = index.get_data1i();
     ++vi;
     while (vi < end) {
+      int v1 = index.get_data1i();
+      ++vi;
       lines->add_vertex(v0);
-      lines->add_vertex(vertices[vi]);
-      nassertr(vi < (int)vertices.size(), this);
-      v0 = vertices[vi];
+      lines->add_vertex(v1);
+      v0 = v1;
       lines->close_primitive();
-      ++vi;
     }
     ++li;
   }
-  nassertr(vi == (int)vertices.size(), lines.p());
+  nassertr(vi == vertices->get_num_vertices() && index.is_at_end(), NULL);
 
   return lines.p();
 }
@@ -162,25 +163,28 @@ decompose_impl() const {
 //       Access: Protected, Virtual
 //  Description: The virtual implementation of do_rotate().
 ////////////////////////////////////////////////////////////////////
-CPTA_ushort qpGeomLinestrips::
+CPT(qpGeomVertexArrayData) qpGeomLinestrips::
 rotate_impl() const {
   // To rotate a line strip, we just reverse the vertices.
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
   CPTA_int ends = get_ends();
-  PTA_ushort new_vertices;
-  new_vertices.reserve(vertices.size());
+  PT(qpGeomVertexArrayData) new_vertices = 
+    new qpGeomVertexArrayData(*vertices);
+  qpGeomVertexReader from(vertices, 0);
+  qpGeomVertexWriter to(new_vertices, 0);
 
   int begin = 0;
   CPTA_int::const_iterator ei;
   for (ei = ends.begin(); ei != ends.end(); ++ei) {
     int end = (*ei);
     for (int vi = end - 1; vi >= begin; --vi) {
-      new_vertices.push_back(vertices[vi]);
+      from.set_vertex(vi);
+      to.set_data1i(from.get_data1i());
     }
     begin = end;
   }
-  nassertr(new_vertices.size() == vertices.size(), CPTA_ushort());
 
+  nassertr(to.is_at_end(), NULL);
   return new_vertices;
 }
 

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

@@ -45,7 +45,7 @@ public:
 
 protected:
   virtual CPT(qpGeomPrimitive) decompose_impl() const;
-  virtual CPTA_ushort rotate_impl() const;
+  virtual CPT(qpGeomVertexArrayData) rotate_impl() const;
 
 public:
   static void register_with_read_factory();

+ 43 - 48
panda/src/gobj/qpgeomPrimitive.I

@@ -65,8 +65,7 @@ set_shade_model(qpGeomPrimitive::ShadeModel shade_model) {
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomPrimitive::UsageHint qpGeomPrimitive::
 get_usage_hint() const {
-  CDReader cdata(_cycler);
-  return cdata->_usage_hint;
+  return get_vertices()->get_usage_hint();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -77,32 +76,31 @@ get_usage_hint() const {
 ////////////////////////////////////////////////////////////////////
 INLINE void qpGeomPrimitive::
 set_usage_hint(qpGeomPrimitive::UsageHint usage_hint) {
-  CDWriter cdata(_cycler);
-  cdata->_usage_hint = usage_hint;
+  modify_vertices()->set_usage_hint(usage_hint);
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::get_num_vertices
-//       Access: Published
-//  Description: Returns the number of vertex vertices used by all the
-//               primitives in this object.
+//     Function: qpGeomPrimitive::get_index_type
+//       Access: Public
+//  Description: Returns the numeric type of the index column.
+//               Normally, this will be either NT_uint16 or NT_uint32.
 ////////////////////////////////////////////////////////////////////
-INLINE int qpGeomPrimitive::
-get_num_vertices() const {
+INLINE qpGeomPrimitive::NumericType qpGeomPrimitive::
+get_index_type() const {
   CDReader cdata(_cycler);
-  return cdata->_vertices.size();
+  return cdata->_index_type;
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::get_vertex
+//     Function: qpGeomPrimitive::get_num_vertices
 //       Access: Published
-//  Description: Returns the ith vertex index in the table.
+//  Description: Returns the number of vertex vertices used by all the
+//               primitives in this object.
 ////////////////////////////////////////////////////////////////////
 INLINE int qpGeomPrimitive::
-get_vertex(int i) const {
+get_num_vertices() const {
   CDReader cdata(_cycler);
-  nassertr(i >= 0 && i < (int)cdata->_vertices.size(), -1);
-  return cdata->_vertices[i];
+  return cdata->_vertices->get_num_vertices();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -162,19 +160,6 @@ get_min_vertex() const {
   return cdata->_min_vertex;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::get_primitive_min_vertex
-//       Access: Published
-//  Description: Returns the minimum vertex index number used by the
-//               nth primitive in this object.
-////////////////////////////////////////////////////////////////////
-INLINE int qpGeomPrimitive::
-get_primitive_min_vertex(int n) const {
-  CPTA_ushort mins = get_mins();
-  nassertr(n >= 0 && n < (int)mins.size(), -1);
-  return mins[n];
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_max_vertex
 //       Access: Published
@@ -192,19 +177,6 @@ get_max_vertex() const {
   return cdata->_max_vertex;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomPrimitive::get_primitive_max_vertex
-//       Access: Published
-//  Description: Returns the maximum vertex index number used by the
-//               nth primitive in this object.
-////////////////////////////////////////////////////////////////////
-INLINE int qpGeomPrimitive::
-get_primitive_max_vertex(int n) const {
-  CPTA_ushort maxs = get_maxs();
-  nassertr(n >= 0 && n < (int)maxs.size(), -1);
-  return maxs[n];
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_data_size_bytes
 //       Access: Published
@@ -214,7 +186,7 @@ get_primitive_max_vertex(int n) const {
 INLINE int qpGeomPrimitive::
 get_data_size_bytes() const {
   CDReader cdata(_cycler);
-  return cdata->_vertices.size() * sizeof(short);
+  return cdata->_vertices->get_data_size_bytes();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -238,12 +210,35 @@ get_modified() const {
 //               attempt to modify the returned array; use
 //               modify_vertices() or set_vertices() for this.
 ////////////////////////////////////////////////////////////////////
-INLINE CPTA_ushort qpGeomPrimitive::
+INLINE const qpGeomVertexArrayData *qpGeomPrimitive::
 get_vertices() const {
   CDReader cdata(_cycler);
   return cdata->_vertices;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_index_stride
+//       Access: Public
+//  Description: A convenience function to return the gap between
+//               successive index numbers, in bytes, of the index
+//               data.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_index_stride() const {
+  return get_vertices()->get_array_format()->get_stride();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_data
+//       Access: Public
+//  Description: A convenience function to return the actual data of
+//               the index array.
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_uchar qpGeomPrimitive::
+get_data() const {
+  return get_vertices()->get_data();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::get_ends
 //       Access: Public
@@ -273,7 +268,7 @@ get_ends() const {
 //               Note that simple primitive types, like triangles, do
 //               not have a mins array.
 ////////////////////////////////////////////////////////////////////
-INLINE CPTA_ushort qpGeomPrimitive::
+INLINE const qpGeomVertexArrayData *qpGeomPrimitive::
 get_mins() const {
   CDReader cdata(_cycler);
   if (!cdata->_got_minmax) {
@@ -295,7 +290,7 @@ get_mins() const {
 //               Note that simple primitive types, like triangles, do
 //               not have a maxs array.
 ////////////////////////////////////////////////////////////////////
-INLINE CPTA_ushort qpGeomPrimitive::
+INLINE const qpGeomVertexArrayData *qpGeomPrimitive::
 get_maxs() const {
   CDReader cdata(_cycler);
   if (!cdata->_got_minmax) {
@@ -313,8 +308,8 @@ get_maxs() const {
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomPrimitive::CData::
 CData() :
-  _usage_hint(UH_unspecified),
   _shade_model(SM_smooth),
+  _index_type(NT_uint16),
   _got_minmax(true),
   _min_vertex(0),
   _max_vertex(0)
@@ -328,8 +323,8 @@ CData() :
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomPrimitive::CData::
 CData(const qpGeomPrimitive::CData &copy) :
-  _usage_hint(copy._usage_hint),
   _shade_model(copy._shade_model),
+  _index_type(copy._index_type),
   _vertices(copy._vertices),
   _ends(copy._ends),
   _mins(copy._mins),

+ 208 - 119
panda/src/gobj/qpgeomPrimitive.cxx

@@ -22,6 +22,8 @@
 #include "qpgeomVertexArrayFormat.h"
 #include "qpgeomVertexColumn.h"
 #include "qpgeomVertexReader.h"
+#include "qpgeomVertexWriter.h"
+#include "qpgeomVertexRewriter.h"
 #include "preparedGraphicsObjects.h"
 #include "internalName.h"
 #include "bamReader.h"
@@ -33,6 +35,16 @@ TypeHandle qpGeomPrimitive::_type_handle;
 PStatCollector qpGeomPrimitive::_decompose_pcollector("Cull:Munge:Decompose");
 PStatCollector qpGeomPrimitive::_rotate_pcollector("Cull:Munge:Rotate");
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::Default Constructor
+//       Access: Protected
+//  Description: Constructs an invalid object.  Only used when reading
+//               from bam.
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::
+qpGeomPrimitive() {
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::Constructor
 //       Access: Published
@@ -40,7 +52,14 @@ PStatCollector qpGeomPrimitive::_rotate_pcollector("Cull:Munge:Rotate");
 ////////////////////////////////////////////////////////////////////
 qpGeomPrimitive::
 qpGeomPrimitive(qpGeomPrimitive::UsageHint usage_hint) {
-  set_usage_hint(usage_hint);
+  CDWriter cdata(_cycler);
+
+  CPT(qpGeomVertexArrayFormat) new_format =
+    qpGeomVertexArrayFormat::register_format
+    (new qpGeomVertexArrayFormat(InternalName::get_index(), 1, 
+                                 cdata->_index_type, C_index));
+
+  cdata->_vertices = new qpGeomVertexArrayData(new_format, usage_hint);
 }
  
 ////////////////////////////////////////////////////////////////////
@@ -78,6 +97,52 @@ get_geom_rendering() const {
   return 0;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::set_index_type
+//       Access: Published
+//  Description: Changes the numeric type of the index column.
+//               Normally, this should be either NT_uint16 or
+//               NT_uint32.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+set_index_type(qpGeomPrimitive::NumericType index_type) {
+  CDWriter cdata(_cycler);
+  cdata->_index_type = index_type;
+  
+  CPT(qpGeomVertexArrayFormat) new_format =
+    qpGeomVertexArrayFormat::register_format
+    (new qpGeomVertexArrayFormat(InternalName::get_index(), 1, index_type, 
+                                 C_index));
+
+  if (cdata->_vertices->get_array_format() != new_format) {
+    PT(qpGeomVertexArrayData) new_vertices = 
+      new qpGeomVertexArrayData(new_format, cdata->_vertices->get_usage_hint());
+    qpGeomVertexReader from(cdata->_vertices, 0);
+    qpGeomVertexWriter to(new_vertices, 0);
+
+    while (!from.is_at_end()) {
+      to.add_data1i(from.get_data1i());
+    }
+    cdata->_vertices = new_vertices;
+    cdata->_got_minmax = false;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_vertex
+//       Access: Published
+//  Description: Returns the ith vertex index in the table.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_vertex(int i) const {
+  CDReader cdata(_cycler);
+  nassertr(i >= 0 && i < (int)cdata->_vertices->get_num_vertices(), -1);
+
+  qpGeomVertexReader index(cdata->_vertices, 0);
+  index.set_vertex(i);
+  return index.get_data1i();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::add_vertex
 //       Access: Published
@@ -90,39 +155,22 @@ get_geom_rendering() const {
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
 add_vertex(int vertex) {
-  unsigned short short_vertex = vertex;
-  nassertv((int)short_vertex == vertex);
-
   CDWriter cdata(_cycler);
 
   int num_primitives = get_num_primitives();
   if (num_primitives > 0 &&
-      (int)cdata->_vertices.size() == get_primitive_end(num_primitives - 1)) {
+      (int)cdata->_vertices->get_num_vertices() == get_primitive_end(num_primitives - 1)) {
     // If we are beginning a new primitive, give the derived class a
     // chance to insert some degenerate vertices.
     append_unused_vertices(cdata->_vertices, vertex);
   }
 
-  cdata->_vertices.push_back(short_vertex);
+  qpGeomVertexWriter index(cdata->_vertices, 0);
+  index.set_vertex(index.get_num_vertices());
 
-  if (cdata->_got_minmax) {
-    cdata->_min_vertex = min(cdata->_min_vertex, short_vertex);
-    cdata->_max_vertex = max(cdata->_max_vertex, short_vertex);
+  index.add_data1i(vertex);
 
-    if (get_num_vertices_per_primitive() == 0) {
-      // Complex primitives also update their per-primitive minmax.
-      size_t pi = cdata->_ends.size();
-      if (pi < cdata->_mins.size()) {
-        cdata->_mins[pi] = min(cdata->_mins[pi], short_vertex);
-        cdata->_maxs[pi] = max(cdata->_maxs[pi], short_vertex);
-      } else {
-        cdata->_mins.push_back(short_vertex);
-        cdata->_maxs.push_back(short_vertex);
-      }
-      nassertv((cdata->_mins.size() == cdata->_ends.size() + 1) &&
-               (cdata->_maxs.size() == cdata->_ends.size() + 1));
-    }
-  }
+  cdata->_got_minmax = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -137,42 +185,25 @@ add_consecutive_vertices(int start, int num_vertices) {
     return;
   }
   int end = (start + num_vertices) - 1;
-  unsigned short short_start = start;
-  unsigned short short_end = end;
-  nassertv((int)short_start == start && (int)short_end == end);
 
   CDWriter cdata(_cycler);
 
   int num_primitives = get_num_primitives();
   if (num_primitives > 0 &&
-      (int)cdata->_vertices.size() == get_primitive_end(num_primitives - 1)) {
+      (int)cdata->_vertices->get_num_vertices() == get_primitive_end(num_primitives - 1)) {
     // If we are beginning a new primitive, give the derived class a
     // chance to insert some degenerate vertices.
     append_unused_vertices(cdata->_vertices, start);
   }
 
-  for (unsigned short v = short_start; v <= short_end; ++v) {
-    cdata->_vertices.push_back(v);
-  }
-
-  if (cdata->_got_minmax) {
-    cdata->_min_vertex = min(cdata->_min_vertex, short_start);
-    cdata->_max_vertex = max(cdata->_max_vertex, short_end);
+  qpGeomVertexWriter index(cdata->_vertices, 0);
+  index.set_vertex(index.get_num_vertices());
 
-    if (get_num_vertices_per_primitive() == 0) {
-      // Complex primitives also update their per-primitive minmax.
-      size_t pi = cdata->_ends.size();
-      if (pi < cdata->_mins.size()) {
-        cdata->_mins[pi] = min(cdata->_mins[pi], short_start);
-        cdata->_maxs[pi] = max(cdata->_maxs[pi], short_end);
-      } else {
-        cdata->_mins.push_back(short_start);
-        cdata->_maxs.push_back(short_end);
-      }
-      nassertv((cdata->_mins.size() == cdata->_ends.size() + 1) &&
-               (cdata->_maxs.size() == cdata->_ends.size() + 1));
-    }
+  for (int v = start; v <= end; ++v) {
+    index.add_data1i(v);
   }
+
+  cdata->_got_minmax = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -214,23 +245,14 @@ close_primitive() {
 #ifndef NDEBUG
     int num_added;
     if (cdata->_ends.empty()) {
-      num_added = (int)cdata->_vertices.size();
+      num_added = (int)cdata->_vertices->get_num_vertices();
     } else {
-      num_added = (int)cdata->_vertices.size() - cdata->_ends.back();
+      num_added = (int)cdata->_vertices->get_num_vertices() - cdata->_ends.back();
       num_added -= get_num_unused_vertices_per_primitive();
     }
     nassertr(num_added >= get_min_num_vertices_per_primitive(), false);
 #endif
-    cdata->_ends.push_back((int)cdata->_vertices.size());
-
-#ifndef NDEBUG
-    if (cdata->_got_minmax) {
-      nassertd((cdata->_mins.size() == cdata->_ends.size()) &&
-               (cdata->_maxs.size() == cdata->_ends.size())) {
-        cdata->_got_minmax = false;
-      }
-    }
-#endif
+    cdata->_ends.push_back((int)cdata->_vertices->get_num_vertices());
 
   } else {
 #ifndef NDEBUG
@@ -240,7 +262,7 @@ close_primitive() {
     int num_vertices_per_primitive = get_num_vertices_per_primitive();
     int num_unused_vertices_per_primitive = get_num_unused_vertices_per_primitive();
 
-    int num_vertices = cdata->_vertices.size();
+    int num_vertices = cdata->_vertices->get_num_vertices();
     nassertr((num_vertices + num_unused_vertices_per_primitive) % (num_vertices_per_primitive + num_unused_vertices_per_primitive) == 0, false)
 #endif
   }
@@ -257,7 +279,8 @@ close_primitive() {
 void qpGeomPrimitive::
 clear_vertices() {
   CDWriter cdata(_cycler);
-  cdata->_vertices.clear();
+  cdata->_vertices = new qpGeomVertexArrayData
+    (cdata->_vertices->get_array_format(), cdata->_vertices->get_usage_hint());
   cdata->_ends.clear();
   cdata->_mins.clear();
   cdata->_maxs.clear();
@@ -274,13 +297,12 @@ void qpGeomPrimitive::
 offset_vertices(int offset) {
   CDWriter cdata(_cycler);
 
-  cdata->_mins.clear();
-  cdata->_maxs.clear();
   cdata->_got_minmax = false;
 
-  PTA_ushort::iterator vi;
-  for (vi = cdata->_vertices.begin(); vi != cdata->_vertices.end(); ++vi) {
-    (*vi) += offset;
+  qpGeomVertexRewriter index(cdata->_vertices, 0);
+
+  while (!index.is_at_end()) {
+    index.set_data1i(index.get_data1i() + offset);
   }
 }
 
@@ -304,7 +326,7 @@ get_num_primitives() const {
   } else {
     // This is a simple primitive type like a triangle: each primitive
     // uses the same number of vertices.
-    return ((int)cdata->_vertices.size() / num_vertices_per_primitive);
+    return ((int)cdata->_vertices->get_num_vertices() / num_vertices_per_primitive);
   }
 }
 
@@ -401,6 +423,38 @@ get_primitive_num_vertices(int n) const {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_primitive_min_vertex
+//       Access: Published
+//  Description: Returns the minimum vertex index number used by the
+//               nth primitive in this object.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_primitive_min_vertex(int n) const {
+  CDReader cdata(_cycler);
+  nassertr(n >= 0 && n < (int)cdata->_mins->get_num_vertices(), -1);
+
+  qpGeomVertexReader index(cdata->_mins, 0);
+  index.set_vertex(n);
+  return index.get_data1i();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_primitive_max_vertex
+//       Access: Published
+//  Description: Returns the maximum vertex index number used by the
+//               nth primitive in this object.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_primitive_max_vertex(int n) const {
+  CDReader cdata(_cycler);
+  nassertr(n >= 0 && n < (int)cdata->_maxs->get_num_vertices(), -1);
+
+  qpGeomVertexReader index(cdata->_maxs, 0);
+  index.set_vertex(n);
+  return index.get_data1i();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::decompose
 //       Access: Published
@@ -446,9 +500,9 @@ rotate() const {
   }
 
   PStatTimer timer(_rotate_pcollector);
-  CPTA_ushort rotated_vertices = rotate_impl();
+  CPT(qpGeomVertexArrayData) rotated_vertices = rotate_impl();
 
-  if (rotated_vertices.is_null()) {
+  if (rotated_vertices == (qpGeomVertexArrayData *)NULL) {
     return this;
   }
 
@@ -466,8 +520,8 @@ rotate() const {
 int qpGeomPrimitive::
 get_num_bytes() const {
   CDReader cdata(_cycler);
-  return (cdata->_vertices.size() + cdata->_mins.size() + cdata->_maxs.size()) * sizeof(short) +
-    cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive);
+  return (cdata->_vertices->get_data_size_bytes() +
+    cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -537,9 +591,14 @@ write(ostream &out, int indent_level) const {
 //               this data.  Use with caution, since there are no
 //               checks that the data will be left in a stable state.
 ////////////////////////////////////////////////////////////////////
-PTA_ushort qpGeomPrimitive::
+qpGeomVertexArrayData *qpGeomPrimitive::
 modify_vertices() {
   CDWriter cdata(_cycler);
+  if (cdata->_vertices->get_ref_count() > 1) {
+    cdata->_vertices = new qpGeomVertexArrayData(*cdata->_vertices);
+  }
+
+  cdata->_modified = qpGeom::get_next_modified();
   cdata->_got_minmax = false;
   return cdata->_vertices;
 }
@@ -552,9 +611,11 @@ modify_vertices() {
 //               the ends list with set_ends() at the same time.
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
-set_vertices(CPTA_ushort vertices) {
+set_vertices(const qpGeomVertexArrayData *vertices) {
   CDWriter cdata(_cycler);
-  cdata->_vertices = (PTA_ushort &)vertices;
+  cdata->_vertices = (qpGeomVertexArrayData *)vertices;
+
+  cdata->_modified = qpGeom::get_next_modified();
   cdata->_got_minmax = false;
 }
 
@@ -573,6 +634,8 @@ set_vertices(CPTA_ushort vertices) {
 PTA_int qpGeomPrimitive::
 modify_ends() {
   CDWriter cdata(_cycler);
+
+  cdata->_modified = qpGeom::get_next_modified();
   cdata->_got_minmax = false;
   return cdata->_ends;
 }
@@ -593,6 +656,8 @@ void qpGeomPrimitive::
 set_ends(CPTA_int ends) {
   CDWriter cdata(_cycler);
   cdata->_ends = (PTA_int &)ends;
+
+  cdata->_modified = qpGeom::get_next_modified();
   cdata->_got_minmax = false;
 }
 
@@ -782,11 +847,11 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
 
   CDReader cdata(_cycler);
 
+  qpGeomVertexReader index(cdata->_vertices, 0);
+
   if (got_mat) {
-    PTA_ushort::const_iterator ii;
-    for (ii = cdata->_vertices.begin(); ii != cdata->_vertices.end(); ++ii) {
-      int index = (int)(*ii);
-      reader.set_vertex(index);
+    while (!index.is_at_end()) {
+      reader.set_vertex(index.get_data1i());
       const LVecBase3f &vertex = reader.get_data3f();
       
       if (found_any) {
@@ -803,10 +868,8 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
       }
     }
   } else {
-    PTA_ushort::const_iterator ii;
-    for (ii = cdata->_vertices.begin(); ii != cdata->_vertices.end(); ++ii) {
-      int index = (int)(*ii);
-      reader.set_vertex(index);
+    while (!index.is_at_end()) {
+      reader.set_vertex(index.get_data1i());
       LPoint3f vertex = mat.xform_point(reader.get_data3f());
       
       if (found_any) {
@@ -849,11 +912,11 @@ decompose_impl() const {
 //       Access: Protected, Virtual
 //  Description: The virtual implementation of rotate().
 ////////////////////////////////////////////////////////////////////
-CPTA_ushort qpGeomPrimitive::
+CPT(qpGeomVertexArrayData) qpGeomPrimitive::
 rotate_impl() const {
   // The default implementation doesn't even try to do anything.
-  nassertr(false, CPTA_ushort());
-  return CPTA_ushort();
+  nassertr(false, NULL);
+  return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -866,7 +929,7 @@ rotate_impl() const {
 //               vertex that begins the new primitive.
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
-append_unused_vertices(PTA_ushort &, int) {
+append_unused_vertices(qpGeomVertexArrayData *, int) {
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -877,7 +940,7 @@ append_unused_vertices(PTA_ushort &, int) {
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::
 recompute_minmax(qpGeomPrimitive::CDWriter &cdata) {
-  if (cdata->_vertices.empty()) {
+  if (cdata->_vertices->get_num_vertices() == 0) {
     cdata->_min_vertex = 0;
     cdata->_max_vertex = 0;
     cdata->_mins.clear();
@@ -886,55 +949,65 @@ recompute_minmax(qpGeomPrimitive::CDWriter &cdata) {
   } else if (get_num_vertices_per_primitive() == 0) {
     // This is a complex primitive type like a triangle strip; compute
     // the minmax of each primitive (as well as the overall minmax).
-    cdata->_mins = PTA_ushort::empty_array(cdata->_ends.size());
-    cdata->_maxs = PTA_ushort::empty_array(cdata->_ends.size());
-    
+    qpGeomVertexReader index(cdata->_vertices, 0);
+
+    cdata->_mins = new qpGeomVertexArrayData
+      (cdata->_vertices->get_array_format(), UH_unspecified);
+    cdata->_maxs = new qpGeomVertexArrayData
+      (cdata->_vertices->get_array_format(), UH_unspecified);
+
+    qpGeomVertexWriter mins(cdata->_mins, 0);
+    qpGeomVertexWriter maxs(cdata->_maxs, 0);
+
     int pi = 0;
     int vi = 0;
-    int num_vertices = (int)cdata->_vertices.size();
     
-    unsigned short vertex = cdata->_vertices[vi];
+    unsigned int vertex = index.get_data1i();
     cdata->_min_vertex = vertex;
-    cdata->_mins[pi] = vertex;
     cdata->_max_vertex = vertex;
-    cdata->_maxs[pi] = vertex;
+    unsigned int min_prim = vertex;
+    unsigned int max_prim = vertex;
     
     ++vi;
-    while (vi < num_vertices) {
-      unsigned short vertex = cdata->_vertices[vi];
+    while (!index.is_at_end()) {
+      unsigned int vertex = index.get_data1i();
       cdata->_min_vertex = min(cdata->_min_vertex, vertex);
       cdata->_max_vertex = max(cdata->_max_vertex, vertex);
-      
+
       if (vi == cdata->_ends[pi]) {
+        mins.add_data1i(min_prim);
+        maxs.add_data1i(max_prim);
+        min_prim = vertex;
+        max_prim = vertex;
         ++pi;
-        if (pi < (int)cdata->_ends.size()) {
-          cdata->_mins[pi] = vertex;
-          cdata->_maxs[pi] = vertex;
-        }
+
       } else {
-        nassertv(pi < (int)cdata->_ends.size());
-        cdata->_mins[pi] = min(cdata->_mins[pi], vertex);
-        cdata->_maxs[pi] = max(cdata->_maxs[pi], vertex);
+        min_prim = min(min_prim, vertex);
+        max_prim = min(max_prim, vertex);
       }
       
       ++vi;
     }
+    mins.add_data1i(min_prim);
+    maxs.add_data1i(max_prim);
+    nassertv(mins.get_num_vertices() == cdata->_ends.size());
 
   } else {
     // This is a simple primitive type like a triangle; just compute
     // the overall minmax.
-    PTA_ushort::const_iterator ii = cdata->_vertices.begin();
-    cdata->_min_vertex = (*ii);
-    cdata->_max_vertex = (*ii);
+    qpGeomVertexReader index(cdata->_vertices, 0);
+
     cdata->_mins.clear();
     cdata->_maxs.clear();
-    
-    ++ii;
-    while (ii != cdata->_vertices.end()) {
-      cdata->_min_vertex = min(cdata->_min_vertex, (*ii));
-      cdata->_max_vertex = max(cdata->_max_vertex, (*ii));
-      
-      ++ii;
+
+    unsigned int vertex = index.get_data1i();
+    cdata->_min_vertex = vertex;
+    cdata->_max_vertex = vertex;
+
+    while (!index.is_at_end()) {
+      unsigned int vertex = index.get_data1i();
+      cdata->_min_vertex = min(cdata->_min_vertex, vertex);
+      cdata->_max_vertex = max(cdata->_max_vertex, vertex);
     }
   }
 
@@ -986,13 +1059,29 @@ make_copy() const {
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::CData::
 write_datagram(BamWriter *manager, Datagram &dg) const {
-  dg.add_uint8(_usage_hint);
   dg.add_uint8(_shade_model);
+  dg.add_uint8(_index_type);
 
-  WRITE_PTA(manager, dg, IPD_ushort::write_datagram, _vertices);
+  manager->write_pointer(dg, _vertices);
   WRITE_PTA(manager, dg, IPD_int::write_datagram, _ends);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::CData::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = CycleData::complete_pointers(p_list, manager);
+
+  _vertices = DCAST(qpGeomVertexArrayData, p_list[pi++]);    
+
+  return pi;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::CData::fillin
 //       Access: Public, Virtual
@@ -1002,10 +1091,10 @@ write_datagram(BamWriter *manager, Datagram &dg) const {
 ////////////////////////////////////////////////////////////////////
 void qpGeomPrimitive::CData::
 fillin(DatagramIterator &scan, BamReader *manager) {
-  _usage_hint = (UsageHint)scan.get_uint8();
   _shade_model = (ShadeModel)scan.get_uint8();
-  
-  READ_PTA(manager, scan, IPD_ushort::read_datagram, _vertices);
+  _index_type = (NumericType)scan.get_uint8();
+
+  manager->read_pointer(scan);
   READ_PTA(manager, scan, IPD_int::read_datagram, _ends);
 
   _modified = qpGeom::get_next_modified();

+ 26 - 15
panda/src/gobj/qpgeomPrimitive.h

@@ -21,11 +21,11 @@
 
 #include "pandabase.h"
 #include "qpgeomEnums.h"
+#include "qpgeomVertexArrayData.h"
 #include "typedWritableReferenceCount.h"
 #include "luse.h"
 #include "updateSeq.h"
 #include "pointerTo.h"
-#include "pta_ushort.h"
 #include "pta_int.h"
 #include "pStatCollector.h"
 #include "cycleData.h"
@@ -63,6 +63,9 @@ class FactoryParams;
 //               This is part of the experimental Geom rewrite.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomPrimitive : public TypedWritableReferenceCount, public qpGeomEnums {
+protected:
+  qpGeomPrimitive();
+
 PUBLISHED:
   qpGeomPrimitive(UsageHint usage_hint);
   qpGeomPrimitive(const qpGeomPrimitive &copy);
@@ -79,6 +82,9 @@ PUBLISHED:
   INLINE UsageHint get_usage_hint() const;
   INLINE void set_usage_hint(UsageHint usage_hint);
 
+  INLINE NumericType get_index_type() const;
+  void set_index_type(NumericType index_type);
+
   // The following published methods are provided for safe, high-level
   // iteration through the vertices and sub-primitives within the
   // GeomPrimitive class.  These work correctly regardless of the
@@ -87,7 +93,7 @@ PUBLISHED:
   // composite primitive using these methods.
 
   INLINE int get_num_vertices() const;
-  INLINE int get_vertex(int i) const;
+  int get_vertex(int i) const;
   void add_vertex(int vertex);
   void add_consecutive_vertices(int start, int num_vertices);
   void add_next_vertices(int num_vertices);
@@ -104,9 +110,9 @@ PUBLISHED:
   INLINE int get_primitive_num_faces(int n) const;
 
   INLINE int get_min_vertex() const;
-  INLINE int get_primitive_min_vertex(int n) const;
+  int get_primitive_min_vertex(int n) const;
   INLINE int get_max_vertex() const;
-  INLINE int get_primitive_max_vertex(int n) const;
+  int get_primitive_max_vertex(int n) const;
 
   CPT(qpGeomPrimitive) decompose() const;
   CPT(qpGeomPrimitive) rotate() const;
@@ -131,16 +137,19 @@ public:
   // recommended that application-level code use the above interfaces
   // instead.
 
-  INLINE CPTA_ushort get_vertices() const;
-  PTA_ushort modify_vertices();
-  void set_vertices(CPTA_ushort vertices);
+  INLINE const qpGeomVertexArrayData *get_vertices() const;
+  qpGeomVertexArrayData *modify_vertices();
+  void set_vertices(const qpGeomVertexArrayData *vertices);
+
+  INLINE int get_index_stride() const;
+  INLINE CPTA_uchar get_data() const;
 
   INLINE CPTA_int get_ends() const;
   PTA_int modify_ends();
   void set_ends(CPTA_int ends);
 
-  INLINE CPTA_ushort get_mins() const;
-  INLINE CPTA_ushort get_maxs() const;
+  INLINE const qpGeomVertexArrayData *get_mins() const;
+  INLINE const qpGeomVertexArrayData *get_maxs() const;
 
   virtual int get_num_vertices_per_primitive() const;
   virtual int get_min_num_vertices_per_primitive() const;
@@ -167,8 +176,9 @@ public:
 
 protected:
   virtual CPT(qpGeomPrimitive) decompose_impl() const;
-  virtual CPTA_ushort rotate_impl() const;
-  virtual void append_unused_vertices(PTA_ushort &vertices, int vertex);
+  virtual CPT(qpGeomVertexArrayData) rotate_impl() const;
+  virtual void append_unused_vertices(qpGeomVertexArrayData *vertices, 
+                                      int vertex);
 
 private:
   // A GeomPrimitive keeps a list (actually, a map) of all the
@@ -186,14 +196,15 @@ private:
     INLINE CData(const CData &copy);
     virtual CycleData *make_copy() const;
     virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
+    virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
     virtual void fillin(DatagramIterator &scan, BamReader *manager);
 
-    UsageHint _usage_hint;
     ShadeModel _shade_model;
-    PTA_ushort _vertices;
+    NumericType _index_type;
+    PT(qpGeomVertexArrayData) _vertices;
     PTA_int _ends;
-    PTA_ushort _mins;
-    PTA_ushort _maxs;
+    PT(qpGeomVertexArrayData) _mins;
+    PT(qpGeomVertexArrayData) _maxs;
     UpdateSeq _modified;
 
     bool _got_minmax;

+ 22 - 13
panda/src/gobj/qpgeomTriangles.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "qpgeomTriangles.h"
+#include "qpgeomVertexRewriter.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -110,25 +111,31 @@ draw(GraphicsStateGuardianBase *gsg) const {
 //       Access: Protected, Virtual
 //  Description: The virtual implementation of do_rotate().
 ////////////////////////////////////////////////////////////////////
-CPTA_ushort qpGeomTriangles::
+CPT(qpGeomVertexArrayData) qpGeomTriangles::
 rotate_impl() const {
   // To rotate triangles, we just move one vertex from the front to
   // the back, or vice-versa; but we have to know what direction we're
   // going.
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
   ShadeModel shade_model = get_shade_model();
 
-  PTA_ushort new_vertices;
-  new_vertices.reserve(vertices.size());
+  PT(qpGeomVertexArrayData) new_vertices = 
+    new qpGeomVertexArrayData(*vertices);
+  qpGeomVertexReader from(vertices, 0);
+  qpGeomVertexWriter to(new_vertices, 0);
 
+  int num_vertices = vertices->get_num_vertices();
+  
   switch (shade_model) {
   case SM_flat_first_vertex:
     // Move the first vertex to the end.
     {
-      for (int begin = 0; begin < (int)vertices.size(); begin += 3) {
-        new_vertices.push_back(vertices[begin + 1]);
-        new_vertices.push_back(vertices[begin + 2]);
-        new_vertices.push_back(vertices[begin]);
+      for (int begin = 0; begin < num_vertices; begin += 3) {
+        from.set_vertex(begin + 1);
+        to.set_data1i(from.get_data1i());
+        to.set_data1i(from.get_data1i());
+        from.set_vertex(begin);
+        to.set_data1i(from.get_data1i());
       }
     }
     break;
@@ -136,10 +143,12 @@ rotate_impl() const {
   case SM_flat_last_vertex:
     // Move the last vertex to the front.
     {
-      for (int begin = 0; begin < (int)vertices.size(); begin += 3) {
-        new_vertices.push_back(vertices[begin + 2]);
-        new_vertices.push_back(vertices[begin]);
-        new_vertices.push_back(vertices[begin + 1]);
+      for (int begin = 0; begin < num_vertices; begin += 3) {
+        from.set_vertex(begin + 2);
+        to.set_data1i(from.get_data1i());
+        from.set_vertex(begin);
+        to.set_data1i(from.get_data1i());
+        to.set_data1i(from.get_data1i());
       }
     }
     break;
@@ -149,7 +158,7 @@ rotate_impl() const {
     nassertr(false, vertices);
   }
   
-  nassertr(new_vertices.size() == vertices.size(), vertices);
+  nassertr(to.is_at_end(), NULL);
   return new_vertices;
 }
 

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

@@ -44,7 +44,7 @@ public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;
 
 protected:
-  virtual CPTA_ushort rotate_impl() const;
+  virtual CPT(qpGeomVertexArrayData) rotate_impl() const;
 
 public:
   static void register_with_read_factory();

+ 16 - 13
panda/src/gobj/qpgeomTrifans.cxx

@@ -18,6 +18,7 @@
 
 #include "qpgeomTrifans.h"
 #include "qpgeomTriangles.h"
+#include "qpgeomVertexRewriter.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 
@@ -119,33 +120,35 @@ CPT(qpGeomPrimitive) qpGeomTrifans::
 decompose_impl() const {
   PT(qpGeomTriangles) triangles = new qpGeomTriangles(get_usage_hint());
   triangles->set_shade_model(get_shade_model());
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
+  qpGeomVertexReader index(vertices, 0);
   CPTA_int ends = get_ends();
 
+  int num_vertices = vertices->get_num_vertices();
+
   int vi = 0;
   int li = 0;
   while (li < (int)ends.size()) {
     int end = ends[li];
     nassertr(vi + 2 <= end, triangles.p());
-    nassertr(vi < (int)vertices.size(), this);
-    int v0 = vertices[vi];
+    int v0 = index.get_data1i();
     ++vi;
-    nassertr(vi < (int)vertices.size(), this);
-    int v1 = vertices[vi];
+    int v1 = index.get_data1i();
     ++vi;
     while (vi < end) {
+      int v2 = index.get_data1i();
+      ++vi;
       triangles->add_vertex(v0);
       triangles->add_vertex(v1);
-      triangles->add_vertex(vertices[vi]);
-      nassertr(vi < (int)vertices.size(), this);
-      v1 = vertices[vi];
+      triangles->add_vertex(v2);
+      nassertr(vi < num_vertices, this);
+      v1 = v2;
       triangles->close_primitive();
-      ++vi;
     }
     ++li;
   }
 
-  nassertr(vi == (int)vertices.size(), triangles.p());
+  nassertr(vi == num_vertices && index.is_at_end(), NULL);
 
   return triangles.p();
 }
@@ -155,12 +158,12 @@ decompose_impl() const {
 //       Access: Protected, Virtual
 //  Description: The virtual implementation of do_rotate().
 ////////////////////////////////////////////////////////////////////
-CPTA_ushort qpGeomTrifans::
+CPT(qpGeomVertexArrayData) qpGeomTrifans::
 rotate_impl() const {
   // Actually, we can't rotate fans without chaging the winding order.
   // It's an error to define a flat shade model for a GeomTrifan.
-  nassertr(false, CPTA_ushort());
-  return CPTA_ushort();
+  nassertr(false, NULL);
+  return NULL;
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -44,7 +44,7 @@ public:
 
 protected:
   virtual CPT(qpGeomPrimitive) decompose_impl() const;
-  virtual CPTA_ushort rotate_impl() const;
+  virtual CPT(qpGeomVertexArrayData) rotate_impl() const;
 
 public:
   static void register_with_read_factory();

+ 52 - 42
panda/src/gobj/qpgeomTristrips.cxx

@@ -18,6 +18,7 @@
 
 #include "qpgeomTristrips.h"
 #include "qpgeomTriangles.h"
+#include "qpgeomVertexRewriter.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -134,9 +135,12 @@ CPT(qpGeomPrimitive) qpGeomTristrips::
 decompose_impl() const {
   PT(qpGeomTriangles) triangles = new qpGeomTriangles(get_usage_hint());
   triangles->set_shade_model(get_shade_model());
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
+  qpGeomVertexReader index(vertices, 0);
   CPTA_int ends = get_ends();
 
+  int num_vertices = vertices->get_num_vertices();
+
   // We need a slightly different algorithm for SM_flat_first_vertex
   // than for SM_flat_last_vertex, to preserve the key vertex in the
   // right place.  The remaining shade models can use either
@@ -149,35 +153,34 @@ decompose_impl() const {
     while (li < (int)ends.size()) {
       // Skip unused vertices between tristrips.
       vi += 2;
+      index.set_vertex(vi);
       int end = ends[li];
-      nassertr(vi + 2 <= end, triangles.p());
-      nassertr(vi < (int)vertices.size(), this);
-      int v0 = vertices[vi];
+      nassertr(vi + 2 <= end, NULL);
+      int v0 = index.get_data1i();
       ++vi;
-      nassertr(vi < (int)vertices.size(), this);
-      int v1 = vertices[vi];
+      int v1 = index.get_data1i();
       ++vi;
       bool reversed = false;
       while (vi < end) {
         triangles->add_vertex(v0);
+        int v2 = index.get_data1i();
+        ++vi;
         if (reversed) {
-          triangles->add_vertex(vertices[vi]);
+          triangles->add_vertex(v2);
           triangles->add_vertex(v1);
           reversed = false;
         } else {
           triangles->add_vertex(v1);
-          triangles->add_vertex(vertices[vi]);
+          triangles->add_vertex(v2);
           reversed = true;
         }
         v0 = v1;
-        nassertr(vi < (int)vertices.size(), this);
-        v1 = vertices[vi];
+        v1 = v2;
         triangles->close_primitive();
-        ++vi;
       }
       ++li;
     }
-    nassertr(vi == (int)vertices.size(), triangles.p());
+    nassertr(vi == num_vertices && index.is_at_end(), NULL);
 
   } else {
     // Preserve the last vertex of each component triangle as the
@@ -187,13 +190,12 @@ decompose_impl() const {
     while (li < (int)ends.size()) {
       // Skip unused vertices between tristrips.
       vi += 2;
+      index.set_vertex(vi);
       int end = ends[li];
-      nassertr(vi + 2 <= end, triangles.p());
-      nassertr(vi < (int)vertices.size(), this);
-      int v0 = vertices[vi];
+      nassertr(vi + 2 <= end, NULL);
+      int v0 = index.get_data1i();
       ++vi;
-      nassertr(vi < (int)vertices.size(), this);
-      int v1 = vertices[vi];
+      int v1 = index.get_data1i();
       ++vi;
       bool reversed = false;
       while (vi < end) {
@@ -206,16 +208,16 @@ decompose_impl() const {
           triangles->add_vertex(v1);
           reversed = true;
         }
-        triangles->add_vertex(vertices[vi]);
+        int v2 = index.get_data1i();
+        ++vi;
+        triangles->add_vertex(v2);
         v0 = v1;
-        nassertr(vi < (int)vertices.size(), this);
-        v1 = vertices[vi];
+        v1 = v2;
         triangles->close_primitive();
-        ++vi;
       }
       ++li;
     }
-    nassertr(vi == (int)vertices.size(), triangles.p());
+    nassertr(vi == num_vertices && index.is_at_end(), NULL);
   }
 
   return triangles.p();
@@ -226,21 +228,24 @@ decompose_impl() const {
 //       Access: Protected, Virtual
 //  Description: The virtual implementation of do_rotate().
 ////////////////////////////////////////////////////////////////////
-CPTA_ushort qpGeomTristrips::
+CPT(qpGeomVertexArrayData) qpGeomTristrips::
 rotate_impl() const {
   // To rotate a triangle strip with an even number of vertices, we
   // just reverse the vertices.  But if we have an odd number of
   // vertices, that doesn't work--in fact, nothing works (without also
   // changing the winding order), so we don't allow an odd number of
   // vertices in a flat-shaded tristrip.
-  CPTA_ushort vertices = get_vertices();
+  CPT(qpGeomVertexArrayData) vertices = get_vertices();
   CPTA_int ends = get_ends();
-  PTA_ushort new_vertices;
-  new_vertices.reserve(vertices.size());
+  PT(qpGeomVertexArrayData) new_vertices = 
+    new qpGeomVertexArrayData(*vertices);
+  qpGeomVertexReader from(vertices, 0);
+  qpGeomVertexWriter to(new_vertices, 0);
 
   bool any_odd = false;
 
   int begin = 0;
+  int last_added = 0;
   CPTA_int::const_iterator ei;
   for (ei = ends.begin(); ei != ends.end(); ++ei) {
     int end = (*ei);
@@ -248,27 +253,25 @@ rotate_impl() const {
 
     if (begin != 0) {
       // Copy in the unused vertices between tristrips.
-      new_vertices.push_back(new_vertices.back());
-      new_vertices.push_back(vertices[end - 1]);
+      to.set_data1i(last_added);
+      from.set_vertex(end - 1);
+      to.set_data1i(from.get_data1i());
       begin += 2;
     }
 
-    if ((num_vertices & 1) == 0) {
-      for (int vi = end - 1; vi >= begin; --vi) {
-        new_vertices.push_back(vertices[vi]);
-      }
-    } else {
-      any_odd = true;
+    // If this assertion is triggered, there was a triangle strip with
+    // an odd number of vertices, which is not allowed.
+    nassertr((num_vertices & 1) == 0, NULL);
+    for (int vi = end - 1; vi >= begin; --vi) {
+      from.set_vertex(vi);
+      last_added = from.get_data1i();
+      to.set_data1i(last_added);
     }
 
     begin = end;
   }
-  nassertr(new_vertices.size() == vertices.size(), vertices);
 
-  // If this assertion is triggered, there was a triangle strip with
-  // an odd number of vertices and either SM_flat_first_vertex or
-  // SM_flat_last_vertex specified--which is not allowed.
-  nassertr(!any_odd, CPTA_ushort());
+  nassertr(to.is_at_end(), NULL);
   return new_vertices;
 }
 
@@ -282,9 +285,16 @@ rotate_impl() const {
 //               vertex that begins the new primitive.
 ////////////////////////////////////////////////////////////////////
 void qpGeomTristrips::
-append_unused_vertices(PTA_ushort &vertices, int vertex) {
-  vertices.push_back(vertices.back());
-  vertices.push_back(vertex);
+append_unused_vertices(qpGeomVertexArrayData *vertices, int vertex) {
+  qpGeomVertexReader from(vertices, 0);
+  from.set_vertex(from.get_num_vertices() - 1);
+  int prev = from.get_data1i();
+
+  qpGeomVertexWriter to(vertices, 0);
+  to.set_vertex(to.get_num_vertices());
+
+  to.add_data1i(prev);
+  to.add_data1i(vertex);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
panda/src/gobj/qpgeomTristrips.h

@@ -45,8 +45,9 @@ public:
 
 protected:
   virtual CPT(qpGeomPrimitive) decompose_impl() const;
-  virtual CPTA_ushort rotate_impl() const;
-  virtual void append_unused_vertices(PTA_ushort &vertices, int vertex);
+  virtual CPT(qpGeomVertexArrayData) rotate_impl() const;
+  virtual void append_unused_vertices(qpGeomVertexArrayData *vertices, 
+                                      int vertex);
 
 public:
   static void register_with_read_factory();

+ 4 - 0
panda/src/gobj/qpgeomVertexColumn.cxx

@@ -47,6 +47,10 @@ setup() {
     _component_bytes = 2;  // sizeof(PN_uint16)
     break;
 
+  case NT_uint32:
+    _component_bytes = 4;  // sizeof(PN_uint32)
+    break;
+
   case NT_uint8:
     _component_bytes = 1;
     break;

+ 75 - 33
panda/src/gobj/qpgeomVertexReader.I

@@ -25,15 +25,9 @@
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomVertexReader::
 qpGeomVertexReader(const qpGeomVertexData *vertex_data) :
-  _vertex_data(vertex_data),
-  _array(0),
-  _column(NULL),
-  _pointer(NULL),
-  _start_vertex(0),
-  _read_vertex(0),
-  _num_vertices(0),
-  _reader(NULL)
+  _vertex_data(vertex_data)
 {
+  initialize();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -45,15 +39,9 @@ qpGeomVertexReader(const qpGeomVertexData *vertex_data) :
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomVertexReader::
 qpGeomVertexReader(const qpGeomVertexData *vertex_data, const string &name) :
-  _vertex_data(vertex_data),
-  _array(0),
-  _column(NULL),
-  _pointer(NULL),
-  _start_vertex(0),
-  _read_vertex(0),
-  _num_vertices(0),
-  _reader(NULL)
+  _vertex_data(vertex_data)
 {
+  initialize();
   set_column(name);
 }
 
@@ -67,18 +55,39 @@ qpGeomVertexReader(const qpGeomVertexData *vertex_data, const string &name) :
 INLINE qpGeomVertexReader::
 qpGeomVertexReader(const qpGeomVertexData *vertex_data, 
                    const InternalName *name) :
-  _vertex_data(vertex_data),
-  _array(0),
-  _column(NULL),
-  _pointer(NULL),
-  _start_vertex(0),
-  _read_vertex(0),
-  _num_vertices(0),
-  _reader(NULL)
+  _vertex_data(vertex_data)
 {
+  initialize();
   set_column(name);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Constructor
+//       Access: Published
+//  Description: Constructs a new reader to process the vertices of
+//               the indicated array only.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexReader::
+qpGeomVertexReader(const qpGeomVertexArrayData *array_data) :
+  _array_data(array_data)
+{
+  initialize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Constructor
+//       Access: Published
+//  Description: Constructs a new reader to process the vertices of
+//               the indicated array only.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexReader::
+qpGeomVertexReader(const qpGeomVertexArrayData *array_data, int column) :
+  _array_data(array_data)
+{
+  initialize();
+  set_column(column);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexReader::Destructor
 //       Access: Published
@@ -96,13 +105,25 @@ INLINE qpGeomVertexReader::
 //     Function: qpGeomVertexReader::get_vertex_data
 //       Access: Published
 //  Description: Returns the vertex data object that the
-//               reader is processing.
+//               reader is processing.  This may return NULL if the
+//               reader was constructed with just an array pointer.
 ////////////////////////////////////////////////////////////////////
 INLINE const qpGeomVertexData *qpGeomVertexReader::
 get_vertex_data() const {
   return _vertex_data;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_array_data
+//       Access: Published
+//  Description: Returns the particular array object that the
+//               reader is currently processing.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexArrayData *qpGeomVertexReader::
+get_array_data() const {
+  return _array_data;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexReader::set_column
 //       Access: Published
@@ -118,8 +139,14 @@ get_vertex_data() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexReader::
 set_column(int column) {
-  return set_column(_vertex_data->get_format()->get_array_with(column),
-                       _vertex_data->get_format()->get_column(column));
+  if (_vertex_data != (const qpGeomVertexData *)NULL) {
+    return set_column(_vertex_data->get_format()->get_array_with(column),
+                      _vertex_data->get_format()->get_column(column));
+  }
+  if (_array_data != (const qpGeomVertexArrayData *)NULL) {
+    return set_column(0, _array_data->get_array_format()->get_column(column));
+  }
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -155,8 +182,15 @@ set_column(const string &name) {
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexReader::
 set_column(const InternalName *name) {
-  return set_column(_vertex_data->get_format()->get_array_with(name),
-                       _vertex_data->get_format()->get_column(name));
+  if (_vertex_data != (const qpGeomVertexData *)NULL) {
+    return set_column(_vertex_data->get_format()->get_array_with(name),
+                      _vertex_data->get_format()->get_column(name));
+  }
+  if (_array_data != (const qpGeomVertexArrayData *)NULL) {
+    return set_column(0, _array_data->get_array_format()->get_column(name));
+  }
+
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -369,9 +403,11 @@ INLINE void qpGeomVertexReader::
 set_pointer(int vertex) {
   nassertv(_column != (qpGeomVertexColumn *)NULL);
   _read_vertex = vertex;
-  CPT(qpGeomVertexArrayData) array_data = _vertex_data->get_array(_array);
-  _pointer = array_data->get_data() + _column->get_start() + _stride * _read_vertex;
-  _num_vertices = array_data->get_num_vertices();
+  if (_vertex_data != (const qpGeomVertexData *)NULL) {
+    _array_data = _vertex_data->get_array(_array);
+  }
+  _pointer = _array_data->get_data() + _column->get_start() + _stride * _read_vertex;
+  _num_vertices = _array_data->get_num_vertices();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -382,8 +418,14 @@ set_pointer(int vertex) {
 ////////////////////////////////////////////////////////////////////
 INLINE const unsigned char *qpGeomVertexReader::
 inc_pointer() {
+#ifndef NDEBUG
   nassertr(_read_vertex < _num_vertices, empty_buffer);
-  nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _read_vertex, empty_buffer);
+  if (_vertex_data != (const qpGeomVertexData *)NULL){ 
+    nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _read_vertex, empty_buffer);
+  } else {
+    nassertr(_pointer == _array_data->get_data() + _column->get_start() + _stride * _read_vertex, empty_buffer);
+  }
+#endif
 
   const unsigned char *orig_pointer = _pointer;
   _pointer += _stride;

+ 101 - 3
panda/src/gobj/qpgeomVertexReader.cxx

@@ -41,14 +41,24 @@ const unsigned char qpGeomVertexReader::empty_buffer[100] = { 0 };
 ////////////////////////////////////////////////////////////////////
 bool qpGeomVertexReader::
 set_column(int array, const qpGeomVertexColumn *column) {
+  if (_vertex_data == (const qpGeomVertexData *)NULL &&
+      _array_data == (const qpGeomVertexArrayData *)NULL) {
+    return false;
+  }
+
   // Delete the old reader, if we've got one.
   if (_reader != (Reader *)NULL) {
     delete _reader;
     _reader = NULL;
   }
 
-  if (array < 0 || array >= _vertex_data->get_num_arrays() || 
-      column == (qpGeomVertexColumn *)NULL) {
+  int num_arrays = 1;
+  if (_vertex_data != (const qpGeomVertexData *)NULL) {
+    num_arrays = _vertex_data->get_num_arrays();
+  }
+
+  if (array < 0 || array >= num_arrays || 
+      column == (const qpGeomVertexColumn *)NULL) {
     // Clear the data type.
     _array = -1;
     _column = NULL;
@@ -61,7 +71,11 @@ set_column(int array, const qpGeomVertexColumn *column) {
   } else {
     _array = array;
     _column = column;
-    _stride = _vertex_data->get_format()->get_array(_array)->get_stride();
+    if (_vertex_data != (const qpGeomVertexData *)NULL) {
+      _stride = _vertex_data->get_format()->get_array(_array)->get_stride();
+    } else {
+      _stride = _array_data->get_array_format()->get_stride();
+    }
 
     set_pointer(_start_vertex);
 
@@ -73,6 +87,22 @@ set_column(int array, const qpGeomVertexColumn *column) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::initialize
+//       Access: Private
+//  Description: Called only by the constructor.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexReader::
+initialize() {
+  _array = 0;
+  _column = NULL;
+  _pointer = NULL;
+  _start_vertex = 0;
+  _read_vertex = 0;
+  _num_vertices = 0;
+  _reader = NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexReader::make_reader
 //       Access: Private
@@ -203,6 +233,9 @@ get_data1f(const unsigned char *pointer) {
   case NT_uint16:
     return *(const PN_uint16 *)pointer;
 
+  case NT_uint32:
+    return *(const PN_uint32 *)pointer;
+
   case NT_packed_dcba:
     {
       PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -246,6 +279,13 @@ get_data2f(const unsigned char *pointer) {
       }
       return _v2;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _v2.set(pi[0], pi[1]);
+      }
+      return _v2;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -306,6 +346,13 @@ get_data3f(const unsigned char *pointer) {
       }
       return _v3;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _v3.set(pi[0], pi[1], pi[2]);
+      }
+      return _v3;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -375,6 +422,13 @@ get_data4f(const unsigned char *pointer) {
       }
       return _v4;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -421,6 +475,9 @@ get_data1i(const unsigned char *pointer) {
   case NT_uint16:
     return *(const PN_uint16 *)pointer;
 
+  case NT_uint32:
+    return *(const PN_uint32 *)pointer;
+
   case NT_packed_dcba:
     {
       PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -470,6 +527,14 @@ get_data2i(const unsigned char *pointer) {
       }
       return _i;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _i[0] = pi[0];
+        _i[1] = pi[1];
+      }
+      return _i;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -539,6 +604,15 @@ get_data3i(const unsigned char *pointer) {
       }
       return _i;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _i[0] = pi[0];
+        _i[1] = pi[1];
+        _i[2] = pi[2];
+      }
+      return _i;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -625,6 +699,16 @@ get_data4i(const unsigned char *pointer) {
       }
       return _i;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _i[0] = pi[0];
+        _i[1] = pi[1];
+        _i[2] = pi[2];
+        _i[3] = pi[3];
+      }
+      return _i;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -746,6 +830,13 @@ get_data4f(const unsigned char *pointer) {
       }
       return _v4;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;
@@ -817,6 +908,13 @@ get_data4f(const unsigned char *pointer) {
       }
       return _v4;
       
+    case NT_uint32:
+      {
+        const PN_uint32 *pi = (const PN_uint32 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+      
     case NT_packed_dcba:
       {
         PN_uint32 dword = *(const PN_uint32 *)pointer;

+ 7 - 0
panda/src/gobj/qpgeomVertexReader.h

@@ -66,9 +66,13 @@ PUBLISHED:
                             const string &name);
   INLINE qpGeomVertexReader(const qpGeomVertexData *vertex_data,
                             const InternalName *name);
+  INLINE qpGeomVertexReader(const qpGeomVertexArrayData *array_data);
+  INLINE qpGeomVertexReader(const qpGeomVertexArrayData *array_data, 
+                            int column);
   INLINE ~qpGeomVertexReader();
 
   INLINE const qpGeomVertexData *get_vertex_data() const;
+  INLINE const qpGeomVertexArrayData *get_array_data() const;
 
   INLINE bool set_column(int column);
   INLINE bool set_column(const string &name);
@@ -99,11 +103,14 @@ PUBLISHED:
 private:
   class Reader;
 
+  void initialize();
+
   INLINE void set_pointer(int vertex);
   INLINE const unsigned char *inc_pointer();
   Reader *make_reader() const;
 
   CPT(qpGeomVertexData) _vertex_data;
+  CPT(qpGeomVertexArrayData) _array_data;
   int _array;
   const qpGeomVertexColumn *_column;
   int _stride;

+ 40 - 0
panda/src/gobj/qpgeomVertexRewriter.I

@@ -60,6 +60,33 @@ qpGeomVertexRewriter(qpGeomVertexData *vertex_data, const InternalName *name) :
   set_column(name);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexRewriter::Constructor
+//       Access: Published
+//  Description: Constructs a new rewriter to process the vertices of
+//               the indicated array only.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexRewriter::
+qpGeomVertexRewriter(qpGeomVertexArrayData *array_data) :
+  qpGeomVertexWriter(array_data),
+  qpGeomVertexReader(array_data)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexRewriter::Constructor
+//       Access: Published
+//  Description: Constructs a new rewriter to process the vertices of
+//               the indicated array only.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexRewriter::
+qpGeomVertexRewriter(qpGeomVertexArrayData *array_data, int column) :
+  qpGeomVertexWriter(array_data),
+  qpGeomVertexReader(array_data)
+{
+  set_column(column);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexRewriter::Destructor
 //       Access: Published
@@ -82,6 +109,19 @@ get_vertex_data() const {
   return qpGeomVertexWriter::get_vertex_data();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexRewriter::get_array_data
+//       Access: Published
+//  Description: Returns the particular array object that the
+//               rewriter is currently processing.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexArrayData *qpGeomVertexRewriter::
+get_array_data() const {
+  nassertr(qpGeomVertexWriter::get_array_data() == 
+           qpGeomVertexReader::get_array_data(), NULL);
+  return qpGeomVertexWriter::get_array_data();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexRewriter::set_column
 //       Access: Published

+ 4 - 0
panda/src/gobj/qpgeomVertexRewriter.h

@@ -49,9 +49,13 @@ PUBLISHED:
                               const string &name);
   INLINE qpGeomVertexRewriter(qpGeomVertexData *vertex_data,
                               const InternalName *name);
+  INLINE qpGeomVertexRewriter(qpGeomVertexArrayData *array_data);
+  INLINE qpGeomVertexRewriter(qpGeomVertexArrayData *array_data, 
+                              int column);
   INLINE ~qpGeomVertexRewriter();
 
   INLINE qpGeomVertexData *get_vertex_data() const;
+  INLINE qpGeomVertexArrayData *get_array_data() const;
 
   INLINE bool set_column(int column);
   INLINE bool set_column(const string &name);

+ 78 - 38
panda/src/gobj/qpgeomVertexWriter.I

@@ -25,15 +25,9 @@
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomVertexWriter::
 qpGeomVertexWriter(qpGeomVertexData *vertex_data) :
-  _vertex_data(vertex_data),
-  _array(0),
-  _column(NULL),
-  _pointer(NULL),
-  _start_vertex(0),
-  _write_vertex(0),
-  _num_vertices(0),
-  _writer(NULL)
+  _vertex_data(vertex_data)
 {
+  initialize();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -45,15 +39,9 @@ qpGeomVertexWriter(qpGeomVertexData *vertex_data) :
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomVertexWriter::
 qpGeomVertexWriter(qpGeomVertexData *vertex_data, const string &name) :
-  _vertex_data(vertex_data),
-  _array(0),
-  _column(NULL),
-  _pointer(NULL),
-  _start_vertex(0),
-  _write_vertex(0),
-  _num_vertices(0),
-  _writer(NULL)
+  _vertex_data(vertex_data)
 {
+  initialize();
   set_column(name);
 }
 
@@ -66,18 +54,39 @@ qpGeomVertexWriter(qpGeomVertexData *vertex_data, const string &name) :
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomVertexWriter::
 qpGeomVertexWriter(qpGeomVertexData *vertex_data, const InternalName *name) :
-  _vertex_data(vertex_data),
-  _array(0),
-  _column(NULL),
-  _pointer(NULL),
-  _start_vertex(0),
-  _write_vertex(0),
-  _num_vertices(0),
-  _writer(NULL)
+  _vertex_data(vertex_data)
 {
+  initialize();
   set_column(name);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexWriter::Constructor
+//       Access: Published
+//  Description: Constructs a new writer to process the vertices of
+//               the indicated array only.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexWriter::
+qpGeomVertexWriter(qpGeomVertexArrayData *array_data) :
+  _array_data(array_data)
+{
+  initialize();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexWriter::Constructor
+//       Access: Published
+//  Description: Constructs a new writer to process the vertices of
+//               the indicated array only.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexWriter::
+qpGeomVertexWriter(qpGeomVertexArrayData *array_data, int column) :
+  _array_data(array_data)
+{
+  initialize();
+  set_column(column);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexWriter::Destructor
 //       Access: Published
@@ -95,13 +104,25 @@ INLINE qpGeomVertexWriter::
 //     Function: qpGeomVertexWriter::get_vertex_data
 //       Access: Published
 //  Description: Returns the vertex data object that the
-//               writer is processing.
+//               writer is processing.  This may return NULL if the
+//               writer was constructed with just an array pointer.
 ////////////////////////////////////////////////////////////////////
 INLINE qpGeomVertexData *qpGeomVertexWriter::
 get_vertex_data() const {
   return _vertex_data;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexWriter::get_array_data
+//       Access: Published
+//  Description: Returns the particular array object that the
+//               writer is currently processing.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexArrayData *qpGeomVertexWriter::
+get_array_data() const {
+  return _array_data;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexWriter::set_column
 //       Access: Published
@@ -117,11 +138,14 @@ get_vertex_data() const {
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexWriter::
 set_column(int column) {
-  if (_vertex_data == (qpGeomVertexData *)NULL) {
-    return false;
+  if (_vertex_data != (qpGeomVertexData *)NULL) {
+    return set_column(_vertex_data->get_format()->get_array_with(column),
+                      _vertex_data->get_format()->get_column(column));
+  }
+  if (_array_data != (qpGeomVertexArrayData *)NULL) {
+    return set_column(0, _array_data->get_array_format()->get_column(column));
   }
-  return set_column(_vertex_data->get_format()->get_array_with(column),
-                    _vertex_data->get_format()->get_column(column));
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -157,11 +181,15 @@ set_column(const string &name) {
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexWriter::
 set_column(const InternalName *name) {
-  if (_vertex_data == (qpGeomVertexData *)NULL) {
-    return false;
+  if (_vertex_data != (qpGeomVertexData *)NULL) {
+    return set_column(_vertex_data->get_format()->get_array_with(name),
+                      _vertex_data->get_format()->get_column(name));
   }
-  return set_column(_vertex_data->get_format()->get_array_with(name),
-                    _vertex_data->get_format()->get_column(name));
+  if (_array_data != (qpGeomVertexArrayData *)NULL) {
+    return set_column(0, _array_data->get_array_format()->get_column(name));
+  }
+
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -679,9 +707,11 @@ INLINE void qpGeomVertexWriter::
 set_pointer(int vertex) {
   nassertv(_column != (qpGeomVertexColumn *)NULL);
   _write_vertex = vertex;
-  PT(qpGeomVertexArrayData) array_data = _vertex_data->modify_array(_array);
-  _pointer = array_data->modify_data() + _column->get_start() + _stride * _write_vertex;
-  _num_vertices = array_data->get_num_vertices();
+  if (_vertex_data != (qpGeomVertexData *)NULL) {
+    _array_data = _vertex_data->modify_array(_array);
+  }
+  _pointer = _array_data->modify_data() + _column->get_start() + _stride * _write_vertex;
+  _num_vertices = _array_data->get_num_vertices();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -692,8 +722,14 @@ set_pointer(int vertex) {
 ////////////////////////////////////////////////////////////////////
 INLINE unsigned char *qpGeomVertexWriter::
 inc_pointer() {
+#ifndef NDEBUG
   nassertr(_write_vertex < _num_vertices, empty_buffer);
-  nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _write_vertex, empty_buffer);
+  if (_vertex_data != (qpGeomVertexData *)NULL){ 
+    nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _write_vertex, empty_buffer);
+  } else {
+    nassertr(_pointer == _array_data->get_data() + _column->get_start() + _stride * _write_vertex, empty_buffer);
+  }
+#endif
 
   unsigned char *orig_pointer = _pointer;
   _pointer += _stride;
@@ -713,7 +749,11 @@ INLINE unsigned char *qpGeomVertexWriter::
 inc_add_pointer() {
   if (_write_vertex >= _num_vertices) {
     // Reset the data pointer.
-    _vertex_data->set_num_vertices(max(_write_vertex + 1, _vertex_data->get_num_vertices()));
+    if (_vertex_data != (qpGeomVertexData *)NULL) {
+      _vertex_data->set_num_vertices(max(_write_vertex + 1, _vertex_data->get_num_vertices()));
+    } else {
+      _array_data->set_num_vertices(max(_write_vertex + 1, _array_data->get_num_vertices()));
+    }
     set_pointer(_write_vertex);
   }
   return inc_pointer();

+ 106 - 4
panda/src/gobj/qpgeomVertexWriter.cxx

@@ -41,7 +41,8 @@ unsigned char qpGeomVertexWriter::empty_buffer[100] = { 0 };
 ////////////////////////////////////////////////////////////////////
 bool qpGeomVertexWriter::
 set_column(int array, const qpGeomVertexColumn *column) {
-  if (_vertex_data == (qpGeomVertexData *)NULL) {
+  if (_vertex_data == (qpGeomVertexData *)NULL &&
+      _array_data == (qpGeomVertexArrayData *)NULL) {
     return false;
   }
 
@@ -51,8 +52,13 @@ set_column(int array, const qpGeomVertexColumn *column) {
     _writer = NULL;
   }
 
-  if (array < 0 || array >= _vertex_data->get_num_arrays() || 
-      column == (qpGeomVertexColumn *)NULL) {
+  int num_arrays = 1;
+  if (_vertex_data != (qpGeomVertexData *)NULL) {
+    num_arrays = _vertex_data->get_num_arrays();
+  }
+
+  if (array < 0 || array >= num_arrays ||
+      column == (const qpGeomVertexColumn *)NULL) {
     // Clear the data type.
     _array = -1;
     _column = NULL;
@@ -65,7 +71,11 @@ set_column(int array, const qpGeomVertexColumn *column) {
   } else {
     _array = array;
     _column = column;
-    _stride = _vertex_data->get_format()->get_array(_array)->get_stride();
+    if (_vertex_data != (qpGeomVertexData *)NULL) {
+      _stride = _vertex_data->get_format()->get_array(_array)->get_stride();
+    } else {
+      _stride = _array_data->get_array_format()->get_stride();
+    }
 
     set_pointer(_start_vertex);
 
@@ -77,6 +87,22 @@ set_column(int array, const qpGeomVertexColumn *column) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexWriter::initialize
+//       Access: Private
+//  Description: Called only by the constructor.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexWriter::
+initialize() {
+  _array = 0;
+  _column = NULL;
+  _pointer = NULL;
+  _start_vertex = 0;
+  _write_vertex = 0;
+  _num_vertices = 0;
+  _writer = NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexWriter::make_writer
 //       Access: Private
@@ -189,6 +215,10 @@ set_data1f(unsigned char *pointer, float data) {
       *(PN_uint16 *)pointer = (unsigned int)data;
       break;
       
+    case NT_uint32:
+      *(PN_uint32 *)pointer = (unsigned int)data;
+      break;
+      
     case NT_packed_dcba:
     case NT_packed_dabc:
       nassertv(false);
@@ -241,6 +271,14 @@ set_data2f(unsigned char *pointer, const LVecBase2f &data) {
       }
       break;
       
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = (unsigned int)data[0];
+        pi[1] = (unsigned int)data[1];
+      }
+      break;
+      
     case NT_packed_dcba:
     case NT_packed_dabc:
       nassertv(false);
@@ -300,6 +338,15 @@ set_data3f(unsigned char *pointer, const LVecBase3f &data) {
       }
       break;
       
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = (unsigned int)data[0];
+        pi[1] = (unsigned int)data[1];
+        pi[2] = (unsigned int)data[2];
+      }
+      break;
+      
     case NT_packed_dcba:
     case NT_packed_dabc:
       nassertv(false);
@@ -361,6 +408,16 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) {
         pi[3] = (unsigned int)data[3];
       }
       break;
+
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = (unsigned int)data[0];
+        pi[1] = (unsigned int)data[1];
+        pi[2] = (unsigned int)data[2];
+        pi[3] = (unsigned int)data[3];
+      }
+      break;
       
     case NT_packed_dcba:
       maybe_scale_color(data);
@@ -398,10 +455,17 @@ set_data1i(unsigned char *pointer, int a) {
     switch (_column->get_numeric_type()) {
     case NT_uint8:
       *pointer = a;
+      nassertv((*pointer) == a);
       break;
       
     case NT_uint16:
       *(PN_uint16 *)pointer = a;
+      nassertv(*(PN_uint16 *)pointer == a);
+      break;
+      
+    case NT_uint32:
+      *(PN_uint32 *)pointer = a;
+      nassertv(*(PN_uint32 *)pointer == a);
       break;
       
     case NT_packed_dcba:
@@ -455,6 +519,14 @@ set_data2i(unsigned char *pointer, int a, int b) {
         pi[1] = b;
       }
       break;
+
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = a;
+        pi[1] = b;
+      }
+      break;
       
     case NT_packed_dcba:
     case NT_packed_dabc:
@@ -513,6 +585,15 @@ set_data3i(unsigned char *pointer, int a, int b, int c) {
         pi[2] = c;
       }
       break;
+
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = a;
+        pi[1] = b;
+        pi[2] = c;
+      }
+      break;
       
     case NT_packed_dcba:
     case NT_packed_dabc:
@@ -574,6 +655,16 @@ set_data4i(unsigned char *pointer, int a, int b, int c, int d) {
         pi[3] = d;
       }
       break;
+
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = a;
+        pi[1] = b;
+        pi[2] = c;
+        pi[3] = d;
+      }
+      break;
       
     case NT_packed_dcba:
       *(PN_uint32 *)pointer = qpGeomVertexData::pack_abcd(d, c, b, a);
@@ -678,6 +769,16 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) {
         pi[3] = (unsigned int)data[3];
       }
       break;
+
+    case NT_uint32:
+      {
+        PN_uint32 *pi = (PN_uint32 *)pointer;
+        pi[0] = (unsigned int)data[0];
+        pi[1] = (unsigned int)data[1];
+        pi[2] = (unsigned int)data[2];
+        pi[3] = (unsigned int)data[3];
+      }
+      break;
       
     case NT_packed_dcba:
       maybe_scale_color(data);
@@ -846,4 +947,5 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) {
 void qpGeomVertexWriter::Writer_uint16_1::
 set_data1i(unsigned char *pointer, int data) {
   *(PN_uint16 *)pointer = data;
+  nassertv(*(PN_uint16 *)pointer == data);
 }

+ 7 - 0
panda/src/gobj/qpgeomVertexWriter.h

@@ -79,9 +79,13 @@ PUBLISHED:
                             const string &name);
   INLINE qpGeomVertexWriter(qpGeomVertexData *vertex_data,
                             const InternalName *name);
+  INLINE qpGeomVertexWriter(qpGeomVertexArrayData *array_data);
+  INLINE qpGeomVertexWriter(qpGeomVertexArrayData *array_data, 
+                            int column);
   INLINE ~qpGeomVertexWriter();
 
   INLINE qpGeomVertexData *get_vertex_data() const;
+  INLINE qpGeomVertexArrayData *get_array_data() const;
 
   INLINE bool set_column(int column);
   INLINE bool set_column(const string &name);
@@ -134,12 +138,15 @@ PUBLISHED:
 private:
   class Writer;
 
+  void initialize();
+
   INLINE void set_pointer(int vertex);
   INLINE unsigned char *inc_pointer();
   INLINE unsigned char *inc_add_pointer();
   Writer *make_writer() const;
 
   PT(qpGeomVertexData) _vertex_data;
+  PT(qpGeomVertexArrayData) _array_data;
   int _array;
   const qpGeomVertexColumn *_column;
   int _stride;

+ 9 - 9
panda/src/pgraph/cullableObject.cxx

@@ -264,18 +264,18 @@ munge_points_to_quads(const CullTraverser *traverser) {
     int num_points = primitive->get_max_vertex() + 1;
     int num_vertices = primitive->get_num_vertices();
     PointData *points = (PointData *)alloca(num_points * sizeof(PointData));
-    unsigned short *vertices = (unsigned short *)alloca(num_vertices * sizeof(unsigned short));
-    unsigned short *vertices_end = vertices + num_vertices;
+    unsigned int *vertices = (unsigned int *)alloca(num_vertices * sizeof(unsigned int));
+    unsigned int *vertices_end = vertices + num_vertices;
 
-    memcpy(vertices, primitive->get_vertices(),
-           num_vertices * sizeof(unsigned short));
-    
-    unsigned short *vi;
+    qpGeomVertexReader index(primitive->get_vertices(), 0);
+    unsigned int *vi;
     for (vi = vertices; vi != vertices_end; ++vi) {
       // Get the point in eye-space coordinates.
-      vertex.set_vertex(*vi);
-      points[*vi]._eye = modelview.xform_point(vertex.get_data3f());
-      points[*vi]._dist = gsg->compute_distance_to(points[*vi]._eye);
+      unsigned int v = index.get_data1i();
+      (*vi) = v;
+      vertex.set_vertex(v);
+      points[v]._eye = modelview.xform_point(vertex.get_data3f());
+      points[v]._dist = gsg->compute_distance_to(points[v]._eye);
     }
   
     // Now sort the points in order from back-to-front so they will