Browse Source

GeomVertexReader

David Rose 21 years ago
parent
commit
f2559a7217

+ 8 - 4
panda/src/display/colorMunger.cxx

@@ -30,10 +30,12 @@ TypeHandle ColorMunger::_type_handle;
 ColorMunger::
 ColorMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
             int num_components,
-            qpGeomVertexDataType::NumericType numeric_type) :
+            qpGeomVertexDataType::NumericType numeric_type,
+            qpGeomVertexDataType::Contents contents) :
   qpGeomMunger(gsg, state),
   _num_components(num_components),
-  _numeric_type(numeric_type)
+  _numeric_type(numeric_type),
+  _contents(contents)
 {
   _color = state->get_color();
   _color_scale = state->get_color_scale();
@@ -69,12 +71,14 @@ munge_data_impl(const qpGeomVertexData *data) {
                 color[2] * cs[2],
                 color[3] * cs[3]);
     }
-    new_data = new_data->set_color(color, _num_components, _numeric_type);
+    new_data = new_data->set_color(color, _num_components, _numeric_type,
+                                   _contents);
 
   } else if (_color_scale != (ColorScaleAttrib *)NULL &&
              _color_scale->has_scale()) {
     const LVecBase4f &cs = _color_scale->get_scale();
-    new_data = new_data->scale_color(cs, _num_components, _numeric_type);
+    new_data = new_data->scale_color(cs, _num_components, _numeric_type,
+                                     _contents);
   }
 
   return qpGeomMunger::munge_data_impl(new_data);

+ 3 - 1
panda/src/display/colorMunger.h

@@ -36,7 +36,8 @@ class EXPCL_PANDA ColorMunger : public qpGeomMunger {
 public:
   ColorMunger(const GraphicsStateGuardianBase *gsg, const RenderState *state,
               int num_components,
-              qpGeomVertexDataType::NumericType numeric_type);
+              qpGeomVertexDataType::NumericType numeric_type,
+              qpGeomVertexDataType::Contents contents);
   virtual ~ColorMunger();
 
 protected:
@@ -47,6 +48,7 @@ protected:
 private:
   int _num_components;
   qpGeomVertexDataType::NumericType _numeric_type;
+  qpGeomVertexDataType::Contents _contents;
   CPT(ColorAttrib) _color;
   CPT(ColorScaleAttrib) _color_scale;
 

+ 2 - 1
panda/src/dxgsg8/dxGeomMunger8.I

@@ -24,7 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 INLINE DXGeomMunger8::
 DXGeomMunger8(GraphicsStateGuardian *gsg, const RenderState *state) :
-  ColorMunger(gsg, state, 1, qpGeomVertexDataType::NT_packed_argb)
+  ColorMunger(gsg, state, 1, qpGeomVertexDataType::NT_packed_8888,
+              qpGeomVertexDataType::C_argb)
 {
 }
 

+ 7 - 4
panda/src/dxgsg8/dxGeomMunger8.cxx

@@ -45,7 +45,8 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
 
   if (vertex_type != (const qpGeomVertexDataType *)NULL) {
     new_array_format->add_data_type
-      (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32);
+      (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
+       qpGeomVertexDataType::C_point);
   } else {
     // If we don't have a vertex type, not much we can do.
     return orig;
@@ -53,12 +54,14 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
 
   if (normal_type != (const qpGeomVertexDataType *)NULL) {
     new_array_format->add_data_type
-      (InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32);
+      (InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
+       qpGeomVertexDataType::C_vector);
   }
 
   if (color_type != (const qpGeomVertexDataType *)NULL) {
     new_array_format->add_data_type
-      (InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb);
+      (InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_8888,
+       qpGeomVertexDataType::C_argb);
   }
 
   // To support multitexture, we will need to add all of the relevant
@@ -67,7 +70,7 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
   if (texcoord_type != (const qpGeomVertexDataType *)NULL) {
     new_array_format->add_data_type
       (InternalName::get_texcoord(), texcoord_type->get_num_values(),
-       qpGeomVertexDataType::NT_float32);
+       qpGeomVertexDataType::NT_float32, qpGeomVertexDataType::C_texcoord);
   }
 
   PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(new_array_format);

+ 10 - 5
panda/src/egg2pg/eggLoader.cxx

@@ -1921,16 +1921,18 @@ make_vertex_data(const EggRenderState *render_state,
   PT(qpGeomVertexArrayFormat) array_format = new qpGeomVertexArrayFormat;
   array_format->add_data_type
     (InternalName::get_vertex(), vertex_pool->get_num_dimensions(),
-     qpGeomVertexDataType::NT_float32);
+     qpGeomVertexDataType::NT_float32, qpGeomVertexDataType::C_point);
 
   if (vertex_pool->has_normals()) {
     array_format->add_data_type
-      (InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32);
+      (InternalName::get_normal(), 3, 
+       qpGeomVertexDataType::NT_float32, qpGeomVertexDataType::C_vector);
   }
 
   if (vertex_pool->has_colors()) {
     array_format->add_data_type
-      (InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb);
+      (InternalName::get_color(), 1, 
+       qpGeomVertexDataType::NT_packed_8888, qpGeomVertexDataType::C_argb);
   }
 
   vector_string uv_names;
@@ -1942,7 +1944,9 @@ make_vertex_data(const EggRenderState *render_state,
       name = string();
     }
     PT(InternalName) iname = InternalName::get_texcoord_name(name);
-    array_format->add_data_type(iname, 2, qpGeomVertexDataType::NT_float32);
+    array_format->add_data_type
+      (iname, 2,
+       qpGeomVertexDataType::NT_float32, qpGeomVertexDataType::C_texcoord);
   }
 
   PT(qpGeomVertexFormat) temp_format = new qpGeomVertexFormat(array_format);
@@ -1956,7 +1960,8 @@ make_vertex_data(const EggRenderState *render_state,
     blend_palette = new TransformBlendPalette;
     PT(qpGeomVertexArrayFormat) blend_array_format = new qpGeomVertexArrayFormat;
     blend_array_format->add_data_type
-      (InternalName::get_transform_blend(), 1, qpGeomVertexDataType::NT_uint16);
+      (InternalName::get_transform_blend(), 1, 
+       qpGeomVertexDataType::NT_uint16, qpGeomVertexDataType::C_index);
     temp_format->add_array(blend_array_format);
 
     // We'll also assign the character name to the vertex data, so it

+ 2 - 1
panda/src/glstuff/glGeomMunger_src.I

@@ -24,7 +24,8 @@
 ////////////////////////////////////////////////////////////////////
 INLINE CLP(GeomMunger)::
 CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) :
-  ColorMunger(gsg, state, 4, qpGeomVertexDataType::NT_ufloat8),
+  ColorMunger(gsg, state, 4, qpGeomVertexDataType::NT_uint8,
+              qpGeomVertexDataType::C_rgba),
   _gsg(gsg),
   _texture(state->get_texture()),
   _tex_gen(state->get_tex_gen())

+ 3 - 3
panda/src/glstuff/glGeomMunger_src.cxx

@@ -50,7 +50,7 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
   const qpGeomVertexDataType *color_type = 
     format->get_data_type(InternalName::get_color());
   if (color_type != (qpGeomVertexDataType *)NULL &&
-      color_type->get_numeric_type() == qpGeomVertexDataType::NT_packed_argb) {
+      color_type->get_numeric_type() == qpGeomVertexDataType::NT_packed_8888) {
     // We need to convert the color format; OpenGL doesn't support the
     // byte order of DirectX's packed_argb format.
     int color_array = format->get_array_with(InternalName::get_color());
@@ -60,8 +60,8 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
 
     // Replace the existing color format with the new format.
     new_array_format->add_data_type
-      (InternalName::get_color(), 4, qpGeomVertexDataType::NT_ufloat8,
-       color_type->get_start());
+      (InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8,
+       qpGeomVertexDataType::C_rgba, color_type->get_start());
 
     format = qpGeomVertexFormat::register_format(new_format);
   }

+ 3 - 3
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -2162,7 +2162,7 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
   if (_vertex_data->get_array_info(InternalName::get_color(),
                                    array_data, num_components, numeric_type, 
                                    start, stride) &&
-      numeric_type != qpGeomVertexDataType::NT_packed_argb) {
+      numeric_type != qpGeomVertexDataType::NT_packed_8888) {
     const unsigned char *client_pointer = setup_array_data(array_data);
     GLP(ColorPointer)(num_components, get_numeric_type(numeric_type), 
                       stride, client_pointer + start);
@@ -4435,13 +4435,13 @@ get_numeric_type(qpGeomVertexDataType::NumericType numeric_type) {
   case qpGeomVertexDataType::NT_uint16:
     return GL_UNSIGNED_SHORT;
 
-  case qpGeomVertexDataType::NT_ufloat8:
+  case qpGeomVertexDataType::NT_uint8:
     return GL_UNSIGNED_BYTE;
     
   case qpGeomVertexDataType::NT_float32:
     return GL_FLOAT;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     break;
   }
 

+ 3 - 0
panda/src/gobj/Sources.pp

@@ -36,6 +36,7 @@
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
     qpgeomVertexIterator.h qpgeomVertexIterator.I \
+    qpgeomVertexReader.h qpgeomVertexReader.I \
     indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     material.I material.h materialPool.I materialPool.h  \
@@ -81,6 +82,7 @@
     qpgeomVertexDataType.cxx \
     qpgeomVertexFormat.cxx \
     qpgeomVertexIterator.cxx \
+    qpgeomVertexReader.cxx \
     indexBufferContext.cxx \
     material.cxx  \
     internalName.cxx \
@@ -124,6 +126,7 @@
     qpgeomVertexDataType.h qpgeomVertexDataType.I \
     qpgeomVertexFormat.h qpgeomVertexFormat.I \
     qpgeomVertexIterator.h qpgeomVertexIterator.I \
+    qpgeomVertexReader.h qpgeomVertexReader.I \
     indexBufferContext.I indexBufferContext.h \
     internalName.I internalName.h \
     material.I material.h \

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

@@ -28,3 +28,4 @@
 #include "qpgeomVertexDataType.cxx"
 #include "qpgeomVertexFormat.cxx"
 #include "qpgeomVertexIterator.cxx"
+#include "qpgeomVertexReader.cxx"

+ 29 - 17
panda/src/gobj/qpgeomVertexArrayFormat.cxx

@@ -48,14 +48,15 @@ qpGeomVertexArrayFormat() :
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexArrayFormat::
 qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
-                        qpGeomVertexDataType::NumericType numeric_type0) :
+                        qpGeomVertexDataType::NumericType numeric_type0,
+                        qpGeomVertexDataType::Contents contents0) :
   _is_registered(false),
   _stride(0),
   _total_bytes(0),
   _pad_to(1),
   _data_types_unsorted(false)
 {
-  add_data_type(name0, num_components0, numeric_type0);
+  add_data_type(name0, num_components0, numeric_type0, contents0);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -66,16 +67,18 @@ qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
 qpGeomVertexArrayFormat::
 qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
                         qpGeomVertexDataType::NumericType numeric_type0,
+                        qpGeomVertexDataType::Contents contents0,
                         const InternalName *name1, int num_components1,
-                        qpGeomVertexDataType::NumericType numeric_type1) :
+                        qpGeomVertexDataType::NumericType numeric_type1,
+                        qpGeomVertexDataType::Contents contents1) :
   _is_registered(false),
   _stride(0),
   _total_bytes(0),
   _pad_to(1),
   _data_types_unsorted(false)
 {
-  add_data_type(name0, num_components0, numeric_type0);
-  add_data_type(name1, num_components1, numeric_type1);
+  add_data_type(name0, num_components0, numeric_type0, contents0);
+  add_data_type(name1, num_components1, numeric_type1, contents1);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -86,19 +89,22 @@ qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
 qpGeomVertexArrayFormat::
 qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
                         qpGeomVertexDataType::NumericType numeric_type0,
+                        qpGeomVertexDataType::Contents contents0,
                         const InternalName *name1, int num_components1,
                         qpGeomVertexDataType::NumericType numeric_type1,
+                        qpGeomVertexDataType::Contents contents1,
                         const InternalName *name2, int num_components2,
-                        qpGeomVertexDataType::NumericType numeric_type2) :
+                        qpGeomVertexDataType::NumericType numeric_type2,
+                        qpGeomVertexDataType::Contents contents2) :
   _is_registered(false),
   _stride(0),
   _total_bytes(0),
   _pad_to(1),
   _data_types_unsorted(false)
 {
-  add_data_type(name0, num_components0, numeric_type0);
-  add_data_type(name1, num_components1, numeric_type1);
-  add_data_type(name2, num_components2, numeric_type2);
+  add_data_type(name0, num_components0, numeric_type0, contents0);
+  add_data_type(name1, num_components1, numeric_type1, contents1);
+  add_data_type(name2, num_components2, numeric_type2, contents2);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -109,22 +115,26 @@ qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
 qpGeomVertexArrayFormat::
 qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
                         qpGeomVertexDataType::NumericType numeric_type0,
+                        qpGeomVertexDataType::Contents contents0,
                         const InternalName *name1, int num_components1,
                         qpGeomVertexDataType::NumericType numeric_type1,
+                        qpGeomVertexDataType::Contents contents1,
                         const InternalName *name2, int num_components2,
                         qpGeomVertexDataType::NumericType numeric_type2,
+                        qpGeomVertexDataType::Contents contents2,
                         const InternalName *name3, int num_components3,
-                        qpGeomVertexDataType::NumericType numeric_type3) :
+                        qpGeomVertexDataType::NumericType numeric_type3,
+                        qpGeomVertexDataType::Contents contents3) :
   _is_registered(false),
   _stride(0),
   _total_bytes(0),
   _pad_to(1),
   _data_types_unsorted(false)
 {
-  add_data_type(name0, num_components0, numeric_type0);
-  add_data_type(name1, num_components1, numeric_type1);
-  add_data_type(name2, num_components2, numeric_type2);
-  add_data_type(name3, num_components3, numeric_type3);
+  add_data_type(name0, num_components0, numeric_type0, contents0);
+  add_data_type(name1, num_components1, numeric_type1, contents1);
+  add_data_type(name2, num_components2, numeric_type2, contents2);
+  add_data_type(name3, num_components3, numeric_type3, contents3);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -194,17 +204,19 @@ qpGeomVertexArrayFormat::
 ////////////////////////////////////////////////////////////////////
 int qpGeomVertexArrayFormat::
 add_data_type(const InternalName *name, int num_components, 
-              qpGeomVertexDataType::NumericType numeric_type, int start) {
+              qpGeomVertexDataType::NumericType numeric_type, 
+              qpGeomVertexDataType::Contents contents, int start) {
   if (start < 0) {
     start = _total_bytes;
 
-    qpGeomVertexDataType temp_data_type(name, num_components, numeric_type, 0);
+    qpGeomVertexDataType temp_data_type
+      (name, num_components, numeric_type, contents, 0);
     int pad_to = temp_data_type.get_component_bytes();
     start = ((start + pad_to - 1) / pad_to) * pad_to;
   }
 
   return add_data_type(qpGeomVertexDataType(name, num_components, 
-                                            numeric_type, start));
+                                            numeric_type, contents, start));
 }
 
 ////////////////////////////////////////////////////////////////////

+ 15 - 4
panda/src/gobj/qpgeomVertexArrayFormat.h

@@ -53,25 +53,35 @@ PUBLISHED:
   qpGeomVertexArrayFormat();
   qpGeomVertexArrayFormat(const qpGeomVertexArrayFormat &copy);
   qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
-                          qpGeomVertexDataType::NumericType numeric_type0);
+                          qpGeomVertexDataType::NumericType numeric_type0,
+                          qpGeomVertexDataType::Contents contents0);
   qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
                           qpGeomVertexDataType::NumericType numeric_type0,
+                          qpGeomVertexDataType::Contents contents0,
                           const InternalName *name1, int num_components1,
-                          qpGeomVertexDataType::NumericType numeric_type1);
+                          qpGeomVertexDataType::NumericType numeric_type1,
+                          qpGeomVertexDataType::Contents contents1);
   qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
                           qpGeomVertexDataType::NumericType numeric_type0,
+                          qpGeomVertexDataType::Contents contents0,
                           const InternalName *name1, int num_components1,
                           qpGeomVertexDataType::NumericType numeric_type1,
+                          qpGeomVertexDataType::Contents contents1,
                           const InternalName *name2, int num_components2,
-                          qpGeomVertexDataType::NumericType numeric_type2);
+                          qpGeomVertexDataType::NumericType numeric_type2,
+                          qpGeomVertexDataType::Contents contents2);
   qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
                           qpGeomVertexDataType::NumericType numeric_type0,
+                          qpGeomVertexDataType::Contents contents0,
                           const InternalName *name1, int num_components1,
                           qpGeomVertexDataType::NumericType numeric_type1,
+                          qpGeomVertexDataType::Contents contents1,
                           const InternalName *name2, int num_components2,
                           qpGeomVertexDataType::NumericType numeric_type2,
+                          qpGeomVertexDataType::Contents contents2,
                           const InternalName *name3, int num_components3,
-                          qpGeomVertexDataType::NumericType numeric_type3);
+                          qpGeomVertexDataType::NumericType numeric_type3,
+                          qpGeomVertexDataType::Contents contents3);
   void operator = (const qpGeomVertexArrayFormat &copy);
   ~qpGeomVertexArrayFormat();
 
@@ -85,6 +95,7 @@ PUBLISHED:
 
   int add_data_type(const InternalName *name, int num_components,
                     qpGeomVertexDataType::NumericType numeric_type,
+                    qpGeomVertexDataType::Contents contents,
                     int start = -1);
   int add_data_type(const qpGeomVertexDataType &data_type);
   void remove_data_type(const InternalName *name);

+ 23 - 18
panda/src/gobj/qpgeomVertexData.cxx

@@ -18,6 +18,7 @@
 
 #include "qpgeomVertexData.h"
 #include "qpgeomVertexIterator.h"
+#include "qpgeomVertexReader.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -358,7 +359,8 @@ convert_to(const qpGeomVertexFormat *new_format) const {
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomVertexData) qpGeomVertexData::
 scale_color(const LVecBase4f &color_scale, int num_components,
-            qpGeomVertexDataType::NumericType numeric_type) const {
+            qpGeomVertexDataType::NumericType numeric_type,
+            qpGeomVertexDataType::Contents contents) const {
   int old_color_array = _format->get_array_with(InternalName::get_color());
   if (old_color_array == -1) {
     // Oops, no color anyway.
@@ -376,7 +378,7 @@ scale_color(const LVecBase4f &color_scale, int num_components,
 
   PT(qpGeomVertexData) new_data = replace_data_type
     (InternalName::get_color(), num_components, numeric_type,
-     get_usage_hint(), true);
+     contents, get_usage_hint(), true);
 
   // Now go through and apply the scale, copying it to the new data.
   qpGeomVertexIterator from(this, InternalName::get_color());
@@ -385,9 +387,9 @@ scale_color(const LVecBase4f &color_scale, int num_components,
   for (int i = 0; i < num_vertices; i++) {
     Colorf color = from.get_data4f();
     to.set_data4f(color[0] * color_scale[0],
-                 color[1] * color_scale[1],
-                 color[2] * color_scale[2],
-                 color[3] * color_scale[3]);
+                  color[1] * color_scale[1],
+                  color[2] * color_scale[2],
+                  color[3] * color_scale[3]);
   }
 
   return new_data;
@@ -405,7 +407,8 @@ scale_color(const LVecBase4f &color_scale, int num_components,
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomVertexData) qpGeomVertexData::
 set_color(const Colorf &color, int num_components,
-          qpGeomVertexDataType::NumericType numeric_type) const {
+          qpGeomVertexDataType::NumericType numeric_type,
+          qpGeomVertexDataType::Contents contents) const {
   int num_vertices = get_num_vertices();
 
   if (gobj_cat.is_debug()) {
@@ -417,7 +420,7 @@ set_color(const Colorf &color, int num_components,
 
   PT(qpGeomVertexData) new_data = replace_data_type
     (InternalName::get_color(), num_components, numeric_type,
-     get_usage_hint(), true);
+     contents, get_usage_hint(), true);
 
   // Now go through and set the new color value.
   qpGeomVertexIterator to(new_data, InternalName::get_color());
@@ -489,6 +492,7 @@ animate_vertices() const {
 PT(qpGeomVertexData) qpGeomVertexData::
 replace_data_type(const InternalName *name, int num_components,
                   qpGeomVertexDataType::NumericType numeric_type,
+                  qpGeomVertexDataType::Contents contents,
                   qpGeomUsageHint::UsageHint usage_hint,
                   bool keep_animation) const {
   PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*_format);
@@ -515,7 +519,7 @@ replace_data_type(const InternalName *name, int num_components,
   int new_type_array = -1;
   if (num_components != 0) {
     PT(qpGeomVertexArrayFormat) type_array_format = 
-      new qpGeomVertexArrayFormat(name, num_components, numeric_type);
+      new qpGeomVertexArrayFormat(name, num_components, numeric_type, contents);
     new_type_array = new_format->add_array(type_array_format);
   }
     
@@ -637,7 +641,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
       
     break;
 
-  case qpGeomVertexDataType::NT_ufloat8:
+  case qpGeomVertexDataType::NT_uint8:
     {
       int i = 0;
       int min_values = min(num_values, data_type->get_num_values());
@@ -655,7 +659,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
     }
     break;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     {
       if (num_values == 4) {
         *(PN_uint32 *)&array_data[element] = pack_argb(data);
@@ -734,7 +738,7 @@ get_data(int array, const qpGeomVertexDataType *data_type,
     }
     break;
 
-  case qpGeomVertexDataType::NT_ufloat8:
+  case qpGeomVertexDataType::NT_uint8:
     {
       int i = 0;
       int min_values = min(num_values, data_type->get_num_values());
@@ -751,7 +755,7 @@ get_data(int array, const qpGeomVertexDataType *data_type,
     }
     break;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     {
       if (num_values == 4) {
         unpack_argb(data, *(PN_uint32 *)&array_data[element]);
@@ -841,7 +845,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
       
     break;
 
-  case qpGeomVertexDataType::NT_ufloat8:
+  case qpGeomVertexDataType::NT_uint8:
     {
       int i = 0;
       int min_values = min(num_values, data_type->get_num_values());
@@ -858,7 +862,7 @@ set_data(int array, const qpGeomVertexDataType *data_type,
     }
     break;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     {
       if (num_values == 4) {
         *(PN_uint32 *)&array_data[element] = pack_argb(data);
@@ -929,7 +933,7 @@ get_data(int array, const qpGeomVertexDataType *data_type,
     }
     break;
 
-  case qpGeomVertexDataType::NT_ufloat8:
+  case qpGeomVertexDataType::NT_uint8:
     {
       int i = 0;
       int min_values = min(num_values, data_type->get_num_values());
@@ -946,7 +950,7 @@ get_data(int array, const qpGeomVertexDataType *data_type,
     }
     break;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     {
       if (num_values == 4) {
         unpack_argb(data, *(PN_uint32 *)&array_data[element]);
@@ -1189,6 +1193,7 @@ make_animated_vertices(qpGeomVertexData::CDWriter &cdata) {
   // array.
   cdata->_animated_vertices = replace_data_type
     (InternalName::get_transform_blend(), 0, qpGeomVertexDataType::NT_uint16,
+     qpGeomVertexDataType::C_index,
      min(get_usage_hint(), qpGeomUsageHint::UH_dynamic), false);
 
   // Now fill it up with the appropriate data.
@@ -1227,8 +1232,8 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata) {
   PT(qpGeomVertexData) new_data = cdata->_animated_vertices;
 
   // Now go through and apply the scale, copying it to the new data.
-  qpGeomVertexIterator from(this, InternalName::get_vertex());
-  qpGeomVertexIterator blendi(this, InternalName::get_transform_blend());
+  qpGeomVertexReader from(this, InternalName::get_vertex());
+  qpGeomVertexReader blendi(this, InternalName::get_transform_blend());
   qpGeomVertexIterator to(new_data, InternalName::get_vertex());
 
   if (from.get_data_type()->get_num_values() == 4) {

+ 5 - 2
panda/src/gobj/qpgeomVertexData.h

@@ -97,16 +97,19 @@ PUBLISHED:
   CPT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
   CPT(qpGeomVertexData) 
     scale_color(const LVecBase4f &color_scale, int num_components,
-                qpGeomVertexDataType::NumericType numeric_type) const;
+                qpGeomVertexDataType::NumericType numeric_type,
+                qpGeomVertexDataType::Contents contents) const;
   CPT(qpGeomVertexData) 
     set_color(const Colorf &color, int num_components,
-              qpGeomVertexDataType::NumericType numeric_type) const;
+              qpGeomVertexDataType::NumericType numeric_type,
+              qpGeomVertexDataType::Contents contents) const;
 
   CPT(qpGeomVertexData) animate_vertices() const;
 
   PT(qpGeomVertexData) 
     replace_data_type(const InternalName *name, int num_components,
                       qpGeomVertexDataType::NumericType numeric_type,
+                      qpGeomVertexDataType::Contents contents,
                       qpGeomUsageHint::UsageHint usage_hint,
                       bool keep_animation) const;
 

+ 17 - 1
panda/src/gobj/qpgeomVertexDataType.I

@@ -28,6 +28,7 @@ qpGeomVertexDataType(const qpGeomVertexDataType &copy) :
   _num_components(copy._num_components),
   _num_values(copy._num_values),
   _numeric_type(copy._numeric_type),
+  _contents(copy._contents),
   _start(copy._start),
   _component_bytes(copy._component_bytes),
   _total_bytes(copy._total_bytes)
@@ -45,6 +46,7 @@ operator = (const qpGeomVertexDataType &copy) {
   _num_components = copy._num_components;
   _num_values = copy._num_values;
   _numeric_type = copy._numeric_type;
+  _contents = copy._contents;
   _start = copy._start;
   _component_bytes = copy._component_bytes;
   _total_bytes = copy._total_bytes;
@@ -85,7 +87,7 @@ get_num_components() const {
 //               into each element.  This is usually, but not always,
 //               the same thing as get_num_components(); the
 //               difference is in the case of a composite numeric type
-//               like NT_packed_argb, which has four numeric values
+//               like NT_packed_8888, which has four numeric values
 //               per component.
 ////////////////////////////////////////////////////////////////////
 INLINE int qpGeomVertexDataType::
@@ -104,6 +106,17 @@ get_numeric_type() const {
   return _numeric_type;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_contents
+//       Access: Published
+//  Description: Returns the token representing the semantic meaning of
+//               the stored value.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexDataType::Contents qpGeomVertexDataType::
+get_contents() const {
+  return _contents;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexDataType::get_start
 //       Access: Published
@@ -168,6 +181,9 @@ compare_to(const qpGeomVertexDataType &other) const {
   if (_numeric_type != other._numeric_type) {
     return (int)_numeric_type - (int)other._numeric_type;
   }
+  if (_contents != other._contents) {
+    return (int)_contents - (int)other._contents;
+  }
   if (_start != other._start) {
     return _start - other._start;
   }

+ 12 - 10
panda/src/gobj/qpgeomVertexDataType.cxx

@@ -25,11 +25,13 @@
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexDataType::
 qpGeomVertexDataType(const InternalName *name, int num_components,
-                     NumericType numeric_type, int start) :
+                     NumericType numeric_type, Contents contents,
+                     int start) :
   _name(name),
   _num_components(num_components),
   _num_values(num_components),
   _numeric_type(numeric_type),
+  _contents(contents),
   _start(start)
 {
   nassertv(num_components > 0 && start >= 0);
@@ -39,11 +41,11 @@ qpGeomVertexDataType(const InternalName *name, int num_components,
     _component_bytes = 2;  // sizeof(PN_uint16)
     break;
 
-  case NT_ufloat8:
+  case NT_uint8:
     _component_bytes = 1;
     break;
 
-  case NT_packed_argb:
+  case NT_packed_8888:
     _component_bytes = 4;  // sizeof(PN_uint32)
     _num_values *= 4;
     break;
@@ -65,7 +67,7 @@ qpGeomVertexDataType(const InternalName *name, int num_components,
 const qpGeomVertexDataType &qpGeomVertexDataType::
 error() {
   static qpGeomVertexDataType error_result
-    (InternalName::get_error(), 1, NT_ufloat8, 0);
+    (InternalName::get_error(), 1, NT_uint8, C_other, 0);
   return error_result;
 }
 
@@ -105,10 +107,10 @@ copy_records(unsigned char *to, int to_stride,
       // An easy case.
     copy_no_convert(to, to_stride, from, from_stride, from_type, num_records);
 
-  } else if (get_numeric_type() == NT_ufloat8 && from_type->get_numeric_type() == NT_packed_argb &&
+  } else if (get_numeric_type() == NT_uint8 && from_type->get_numeric_type() == NT_packed_8888 &&
              get_num_values() == from_type->get_num_values()) {
     copy_argb_to_uint8(to, to_stride, from, from_stride, from_type, num_records);
-  } else if (get_numeric_type() == NT_packed_argb && from_type->get_numeric_type() == NT_ufloat8 &&
+  } else if (get_numeric_type() == NT_packed_8888 && from_type->get_numeric_type() == NT_uint8 &&
              get_num_values() == from_type->get_num_values()) {
     copy_uint8_to_argb(to, to_stride, from, from_stride, from_type, num_records);
   } else {
@@ -230,10 +232,10 @@ get_value(const unsigned char *data, int n) const {
   case NT_uint16:
     return (float)data[n];
 
-  case NT_ufloat8:
+  case NT_uint8:
     return (float)data[n] / 255.0f;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     {
       int element = n / 4;
       const PN_uint32 *int_array = (const PN_uint32 *)data;
@@ -274,11 +276,11 @@ set_value(unsigned char *data, int n, float value) const {
     data[n] = (int)value;
     break;
 
-  case NT_ufloat8:
+  case NT_uint8:
     data[n] = (int)(value * 255.0f);
     break;
 
-  case qpGeomVertexDataType::NT_packed_argb:
+  case qpGeomVertexDataType::NT_packed_8888:
     {
       int element = n / 4;
 

+ 18 - 5
panda/src/gobj/qpgeomVertexDataType.h

@@ -35,14 +35,25 @@
 class EXPCL_PANDA qpGeomVertexDataType {
 PUBLISHED:
   enum NumericType {
-    NT_uint16,       // A short integer 0..65535
-    NT_ufloat8,      // A floating-point number 0..1 packed into a byte
-    NT_float32,      // A true floating-point number
-    NT_packed_argb,  // DirectX style color specification
+    NT_uint8,        // An integer 0..255
+    NT_uint16,       // An integer 0..65535
+    NT_packed_8888,  // DirectX style, four byte values packed in a dword
+    NT_float32,      // A floating-point number
+  };
+
+  enum Contents {
+    C_other,        // Arbitrary meaning, leave it alone
+    C_point,        // A point in 3-space or 4-space
+    C_vector,       // A surface normal, tangent, or binormal
+    C_texcoord,     // A texture coordinate
+    C_rgba,         // RGB or RGBA, OpenGL-style order
+    C_argb,         // RGBA, DirectX-style packed color
+    C_index,        // An index value into some other table
   };
 
   INLINE qpGeomVertexDataType(const InternalName *name, int num_components,
-                              NumericType numeric_type, int start);
+                              NumericType numeric_type, Contents contents,
+                              int start);
   INLINE qpGeomVertexDataType(const qpGeomVertexDataType &copy);
   INLINE void operator = (const qpGeomVertexDataType &copy);
 
@@ -52,6 +63,7 @@ PUBLISHED:
   INLINE int get_num_components() const;
   INLINE int get_num_values() const;
   INLINE NumericType get_numeric_type() const;
+  INLINE Contents get_contents() const;
   INLINE int get_start() const;
   INLINE int get_component_bytes() const;
   INLINE int get_total_bytes() const;
@@ -98,6 +110,7 @@ private:
   int _num_components;
   int _num_values;
   NumericType _numeric_type;
+  Contents _contents;
   int _start;
   int _component_bytes;
   int _total_bytes;

+ 96 - 32
panda/src/gobj/qpgeomVertexFormat.cxx

@@ -526,64 +526,128 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 qpGeomVertexFormat::Registry::
 Registry() {
   _v3 = register_format(new qpGeomVertexArrayFormat
-                        (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32));
+                        (InternalName::get_vertex(), 3, 
+                         qpGeomVertexDataType::NT_float32,
+                         qpGeomVertexDataType::C_point));
 
   _v3n3 = register_format(new qpGeomVertexArrayFormat
-                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32));
+                          (InternalName::get_vertex(), 3, 
+                           qpGeomVertexDataType::NT_float32,
+                           qpGeomVertexDataType::C_point,
+                           InternalName::get_normal(), 3, 
+                           qpGeomVertexDataType::NT_float32,
+                           qpGeomVertexDataType::C_vector));
 
   _v3t2 = register_format(new qpGeomVertexArrayFormat
-                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float32));
+                          (InternalName::get_vertex(), 3, 
+                           qpGeomVertexDataType::NT_float32,
+                           qpGeomVertexDataType::C_point,
+                           InternalName::get_texcoord(), 2, 
+                           qpGeomVertexDataType::NT_float32,
+                           qpGeomVertexDataType::C_texcoord));
 
   _v3n3t2 = register_format(new qpGeomVertexArrayFormat
-                            (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                             InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
-                             InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float32));
+                            (InternalName::get_vertex(), 3, 
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_normal(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_vector,
+                             InternalName::get_texcoord(), 2, 
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_texcoord));
 
   // Define the DirectX-style packed color formats
   _v3cp = register_format(new qpGeomVertexArrayFormat
-                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb));
+                          (InternalName::get_vertex(), 3,
+                           qpGeomVertexDataType::NT_float32,
+                           qpGeomVertexDataType::C_point,
+                           InternalName::get_color(), 1,
+                           qpGeomVertexDataType::NT_packed_8888,
+                           qpGeomVertexDataType::C_argb));
 
   _v3n3cp = register_format(new qpGeomVertexArrayFormat
-                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb));
+                            (InternalName::get_vertex(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_normal(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_color(), 1,
+                             qpGeomVertexDataType::NT_packed_8888,
+                             qpGeomVertexDataType::C_argb));
 
   _v3cpt2 = register_format(new qpGeomVertexArrayFormat
-                            (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                             InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb,
-                             InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float32));
+                            (InternalName::get_vertex(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_color(), 1,
+                             qpGeomVertexDataType::NT_packed_8888,
+                             qpGeomVertexDataType::C_argb,
+                             InternalName::get_texcoord(), 2,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_texcoord));
 
   _v3n3cpt2 = register_format(new qpGeomVertexArrayFormat
-                              (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                               InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
-                               InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb,
-                               InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float32));
+                              (InternalName::get_vertex(), 3,
+                               qpGeomVertexDataType::NT_float32,
+                               qpGeomVertexDataType::C_point,
+                               InternalName::get_normal(), 3,
+                               qpGeomVertexDataType::NT_float32,
+                               qpGeomVertexDataType::C_point,
+                               InternalName::get_color(), 1,
+                               qpGeomVertexDataType::NT_packed_8888,
+                               qpGeomVertexDataType::C_argb,
+                               InternalName::get_texcoord(), 2,
+                               qpGeomVertexDataType::NT_float32,
+                               qpGeomVertexDataType::C_texcoord));
 
   // Define the OpenGL-style per-byte color formats.  This is not the
   // same as a packed format, above, because the resulting byte order
   // is endian-independent.
   _v3c4 = register_format(new qpGeomVertexArrayFormat
-                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_color(), 4, qpGeomVertexDataType::NT_ufloat8));
+                          (InternalName::get_vertex(), 3,
+                           qpGeomVertexDataType::NT_float32,
+                           qpGeomVertexDataType::C_point,
+                           InternalName::get_color(), 4,
+                           qpGeomVertexDataType::NT_uint8,
+                           qpGeomVertexDataType::C_rgba));
 
   _v3n3c4 = register_format(new qpGeomVertexArrayFormat
-                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
-                           InternalName::get_color(), 4, qpGeomVertexDataType::NT_ufloat8));
+                            (InternalName::get_vertex(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_normal(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_color(), 4,
+                             qpGeomVertexDataType::NT_uint8,
+                             qpGeomVertexDataType::C_rgba));
 
   _v3c4t2 = register_format(new qpGeomVertexArrayFormat
-                            (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                             InternalName::get_color(), 4, qpGeomVertexDataType::NT_ufloat8,
-                             InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float32));
+                            (InternalName::get_vertex(), 3,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_point,
+                             InternalName::get_color(), 4,
+                             qpGeomVertexDataType::NT_uint8,
+                             qpGeomVertexDataType::C_rgba,
+                             InternalName::get_texcoord(), 2,
+                             qpGeomVertexDataType::NT_float32,
+                             qpGeomVertexDataType::C_texcoord));
 
   _v3n3c4t2 = register_format(new qpGeomVertexArrayFormat
-                              (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float32,
-                               InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float32,
-                               InternalName::get_color(), 4, qpGeomVertexDataType::NT_ufloat8,
-                               InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float32));
+                              (InternalName::get_vertex(), 3,
+                               qpGeomVertexDataType::NT_float32,
+                               qpGeomVertexDataType::C_point,
+                               InternalName::get_normal(), 3,
+                               qpGeomVertexDataType::NT_float32,
+                               qpGeomVertexDataType::C_point,
+                               InternalName::get_color(), 4,
+                               qpGeomVertexDataType::NT_uint8,
+                               qpGeomVertexDataType::C_rgba,
+                               InternalName::get_texcoord(), 2,
+                               qpGeomVertexDataType::NT_float32,
+                               qpGeomVertexDataType::C_texcoord));
 }
 
 ////////////////////////////////////////////////////////////////////

+ 385 - 0
panda/src/gobj/qpgeomVertexReader.I

@@ -0,0 +1,385 @@
+// Filename: qpgeomVertexReader.I
+// Created by:  drose (25Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Constructor
+//       Access: Published
+//  Description: Constructs a new reader to process the vertices of
+//               the indicated data object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexReader::
+qpGeomVertexReader(const qpGeomVertexData *vertex_data) :
+  _vertex_data(vertex_data),
+  _array(0),
+  _data_type(NULL),
+  _pointer(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _reader(NULL)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Constructor
+//       Access: Published
+//  Description: Constructs a new reader to process the vertices of
+//               the indicated data object.  This flavor creates the
+//               reader specifically to process the named data type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexReader::
+qpGeomVertexReader(const qpGeomVertexData *vertex_data, const string &name) :
+  _vertex_data(vertex_data),
+  _array(0),
+  _data_type(NULL),
+  _pointer(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _reader(NULL)
+{
+  set_data_type(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Constructor
+//       Access: Published
+//  Description: Constructs a new reader to process the vertices of
+//               the indicated data object.  This flavor creates the
+//               reader specifically to process the named data type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexReader::
+qpGeomVertexReader(const qpGeomVertexData *vertex_data, 
+                   const InternalName *name) :
+  _vertex_data(vertex_data),
+  _array(0),
+  _data_type(NULL),
+  _pointer(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _reader(NULL)
+{
+  set_data_type(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexReader::
+~qpGeomVertexReader() {
+  if (_reader != (Reader *)NULL) {
+    delete _reader;
+    _reader = NULL;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_vertex_data
+//       Access: Published
+//  Description: Returns the vertex data object that the
+//               reader is processing.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexData *qpGeomVertexReader::
+get_vertex_data() const {
+  return _vertex_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::set_data_type
+//       Access: Published
+//  Description: Sets up the reader to use the nth data type of the
+//               GeomVertexFormat, numbering from 0.
+//
+//               This also resets the read vertex number to the start
+//               vertex (the same value passed to a previous call to
+//               set_vertex(), or 0 if set_vertex() was never called.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::
+set_data_type(int data_type) {
+  nassertv(_vertex_data->get_format()->get_array_with(data_type) >= 0);
+  set_data_type(_vertex_data->get_format()->get_array_with(data_type),
+                _vertex_data->get_format()->get_data_type(data_type));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::set_data_type
+//       Access: Published
+//  Description: Sets up the reader to use the data type with the
+//               indicated name.
+//
+//               This also resets the read vertex number to the start
+//               vertex (the same value passed to a previous call to
+//               set_vertex(), or 0 if set_vertex() was never called.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::
+set_data_type(const string &name) {
+  set_data_type(InternalName::make(name));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::set_data_type
+//       Access: Published
+//  Description: Sets up the reader to use the data type with the
+//               indicated name.
+//
+//               This also resets the read vertex number to the start
+//               vertex (the same value passed to a previous call to
+//               set_vertex(), or 0 if set_vertex() was never called.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::
+set_data_type(const InternalName *name) {
+  nassertv(_vertex_data->get_format()->get_array_with(name) >= 0);
+  set_data_type(_vertex_data->get_format()->get_array_with(name),
+                _vertex_data->get_format()->get_data_type(name));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_array
+//       Access: Published
+//  Description: Returns the array index containing the data type that
+//               the reader is working on.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexReader::
+get_array() const {
+  return _array;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_data_type
+//       Access: Published
+//  Description: Returns the description of the data type that the
+//               reader is working on.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexDataType *qpGeomVertexReader::
+get_data_type() const {
+  return _data_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::set_vertex
+//       Access: Published
+//  Description: Sets the start, read, and write index to the
+//               indicated value.  The reader will begin traversing
+//               from the given vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::
+set_vertex(int vertex) {
+  _start_vertex = vertex;
+  _read_vertex = vertex;
+  set_pointer();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_start_vertex
+//       Access: Published
+//  Description: Returns the vertex index at which the reader
+//               started.  It will return to this vertex if you reset
+//               the current data_type.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexReader::
+get_start_vertex() const {
+  return _start_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_read_vertex
+//       Access: Published
+//  Description: Returns the current read vertex index of the
+//               reader.  This is the index whose value will be
+//               returned by the next call to get_data*().
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexReader::
+get_read_vertex() const {
+  return _read_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_data1f
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 1-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE float qpGeomVertexReader::
+get_data1f() {
+  return _reader->get_data1f(inc_pointer());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_data2f
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 2-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase2f &qpGeomVertexReader::
+get_data2f() {
+  return _reader->get_data2f(inc_pointer());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_data3f
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 3-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase3f &qpGeomVertexReader::
+get_data3f() {
+  return _reader->get_data3f(inc_pointer());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_data4f
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 4-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase4f &qpGeomVertexReader::
+get_data4f() {
+  return _reader->get_data4f(inc_pointer());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::get_data1i
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 1-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexReader::
+get_data1i() {
+  return _reader->get_data1i(inc_pointer());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::set_pointer
+//       Access: Private
+//  Description: Sets up the internal pointer, etc. to use the vertex
+//               indicated by _start_vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::
+set_pointer() {
+  _read_vertex = _start_vertex;
+  _data = _vertex_data->get_array(_array)->get_data();
+  _pointer = _data.p() + _data_type->get_start() + _stride * _read_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::inc_pointer
+//       Access: Private
+//  Description: Increments to the next vertex, and returns the data
+//               pointer as it was before incrementing.
+////////////////////////////////////////////////////////////////////
+INLINE const unsigned char *qpGeomVertexReader::
+inc_pointer() {
+  const unsigned char *orig_pointer = _pointer;
+  _pointer += _stride;
+  ++_read_vertex;
+  return orig_pointer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::maybe_scale_color
+//       Access: Public
+//  Description: Converts an integer (typically a uint8) value to a
+//               floating-point value.  If the contents value
+//               indicates this is a color value, scales it into the
+//               range 0..1 per convention; otherwise leaves it alone.
+////////////////////////////////////////////////////////////////////
+INLINE float qpGeomVertexReader::Reader::
+maybe_scale_color(unsigned int value) {
+  switch (_data_type->get_contents()) {
+  case qpGeomVertexDataType::C_rgba:
+  case qpGeomVertexDataType::C_argb:
+    return (float)value / 255.0f;
+    
+  default:
+    return (float)value;
+  }
+}
+    
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::maybe_scale_color
+//       Access: Public
+//  Description: Converts a pair of integers into the _v2 member.  See
+//               one-parameter maybe_scale_color() for more info.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::Reader::
+maybe_scale_color(unsigned int a, unsigned int b) {
+  switch (_data_type->get_contents()) {
+  case qpGeomVertexDataType::C_rgba:
+  case qpGeomVertexDataType::C_argb:
+    _v2.set((float)a / 255.0f,
+            (float)b / 255.0f);
+    break;
+    
+  default:
+    _v2.set((float)a, (float)b);
+    break;
+  }
+}
+    
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::maybe_scale_color
+//       Access: Public
+//  Description: Converts a pair of integers into the _v3 member.  See
+//               one-parameter maybe_scale_color() for more info.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::Reader::
+maybe_scale_color(unsigned int a, unsigned int b, unsigned int c) {
+  switch (_data_type->get_contents()) {
+  case qpGeomVertexDataType::C_rgba:
+  case qpGeomVertexDataType::C_argb:
+    _v3.set((float)a / 255.0f,
+            (float)b / 255.0f,
+            (float)c / 255.0f);
+    break;
+    
+  default:
+    _v3.set((float)a, (float)b, (float)c);
+    break;
+  }
+}
+    
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::maybe_scale_color
+//       Access: Public
+//  Description: Converts a pair of integers into the _v4 member.  See
+//               one-parameter maybe_scale_color() for more info.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexReader::Reader::
+maybe_scale_color(unsigned int a, unsigned int b, unsigned int c,
+                  unsigned int d) {
+  switch (_data_type->get_contents()) {
+  case qpGeomVertexDataType::C_rgba:
+  case qpGeomVertexDataType::C_argb:
+    _v4.set((float)a / 255.0f,
+            (float)b / 255.0f,
+            (float)c / 255.0f,
+            (float)d / 255.0f);
+    break;
+    
+  default:
+    _v4.set((float)a, (float)b, (float)c, (float)d);
+    break;
+  }
+}
+    

+ 398 - 0
panda/src/gobj/qpgeomVertexReader.cxx

@@ -0,0 +1,398 @@
+// Filename: qpgeomVertexReader.cxx
+// Created by:  drose (25Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "qpgeomVertexReader.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::set_data_type
+//       Access: Published
+//  Description: Sets up the reader to use the indicated data_type
+//               description on the given array.
+//
+//               This also resets the current read vertex numbers to
+//               the start vertex (the same value passed to a previous
+//               call to set_vertex(), or 0 if set_vertex() was never
+//               called.)
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexReader::
+set_data_type(int array, const qpGeomVertexDataType *data_type) {
+  nassertv(array >= 0 && array < _vertex_data->get_num_arrays());
+  nassertv(data_type != (qpGeomVertexDataType *)NULL);
+  _array = array;
+  _data_type = data_type;
+  _stride = _vertex_data->get_format()->get_array(_array)->get_stride();
+
+  set_pointer();
+
+  // Delete the old reader, if we've got one.
+  if (_reader != (Reader *)NULL) {
+    delete _reader;
+    _reader = NULL;
+  }
+
+  // Now set up a new reader.
+  _reader = make_reader();
+  _reader->_data_type = _data_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::make_reader
+//       Access: Private
+//  Description: Returns a newly-allocated Reader object suitable for
+//               reading the current data type.
+////////////////////////////////////////////////////////////////////
+qpGeomVertexReader::Reader *qpGeomVertexReader::
+make_reader() const {
+  if (_data_type->get_contents() == qpGeomVertexDataType::C_point &&
+      _data_type->get_num_values() < 4) {
+    return new Reader_point;
+
+  } else {
+    switch (_data_type->get_numeric_type()) {
+    case qpGeomVertexDataType::NT_float32:
+      if (sizeof(float) == 4) {
+        switch (_data_type->get_num_components()) {
+        case 3:
+          return new Reader_float_3;
+          
+        default:
+          break;
+        }
+      }
+      break;
+
+    case qpGeomVertexDataType::NT_uint16:
+      switch (_data_type->get_num_components()) {
+      case 1:
+        return new Reader_uint16_1;
+        
+      default:
+        break;
+      }
+
+    default:
+      break;
+    }
+  }
+
+  // If we got here, we have to create a generic reader.
+  return new Reader;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexReader::Reader::
+~Reader() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::get_data1f
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+float qpGeomVertexReader::Reader::
+get_data1f(const unsigned char *pointer) {
+  switch (_data_type->get_numeric_type()) {
+  case qpGeomVertexDataType::NT_uint8:
+    return maybe_scale_color(*pointer);
+
+  case qpGeomVertexDataType::NT_uint16:
+    return *(PN_uint16 *)pointer;
+
+  case qpGeomVertexDataType::NT_packed_8888:
+    {
+      packed_8888 dword;
+      dword._i = *(PN_uint32 *)pointer;
+      return maybe_scale_color(dword._b[0]);
+    }
+
+  case qpGeomVertexDataType::NT_float32:
+    return *(PN_float32 *)pointer;
+  }
+
+  return 0.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::get_data2f
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const LVecBase2f &qpGeomVertexReader::Reader::
+get_data2f(const unsigned char *pointer) {
+  if (_data_type->get_num_values() == 1) {
+    _v2.set(get_data1i(pointer), 0.0f);
+    return _v2;
+
+  } else {
+    switch (_data_type->get_numeric_type()) {
+    case qpGeomVertexDataType::NT_uint8:
+      maybe_scale_color(pointer[0], pointer[1]);
+      return _v2;
+      
+    case qpGeomVertexDataType::NT_uint16:
+      {
+        PN_uint16 *pi = (PN_uint16 *)pointer;
+        _v2.set(pi[0], pi[1]);
+      }
+      return _v2;
+      
+    case qpGeomVertexDataType::NT_packed_8888:
+      {
+        packed_8888 dword;
+        dword._i = *(PN_uint32 *)pointer;
+        maybe_scale_color(dword._b[0], dword._b[1]);
+      }
+      return _v2;
+      
+    case qpGeomVertexDataType::NT_float32:
+      {
+        PN_float32 *pi = (PN_float32 *)pointer;
+        _v2.set(pi[0], pi[1]);
+      }
+      return _v2;
+    }
+  }
+
+  return _v2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::get_data3f
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const LVecBase3f &qpGeomVertexReader::Reader::
+get_data3f(const unsigned char *pointer) {
+  switch (_data_type->get_num_values()) {
+  case 1:
+    _v3.set(get_data1i(pointer), 0.0f, 0.0f);
+    return _v3;
+
+  case 2:
+    {
+      const LVecBase2f &v2 = get_data2f(pointer);
+      _v3.set(v2[0], v2[1], 0.0f);
+    }
+    return _v3;
+
+  default:
+    switch (_data_type->get_numeric_type()) {
+    case qpGeomVertexDataType::NT_uint8:
+      maybe_scale_color(pointer[0], pointer[1], pointer[2]);
+      return _v3;
+      
+    case qpGeomVertexDataType::NT_uint16:
+      {
+        PN_uint16 *pi = (PN_uint16 *)pointer;
+        _v3.set(pi[0], pi[1], pi[2]);
+      }
+      return _v3;
+      
+    case qpGeomVertexDataType::NT_packed_8888:
+      {
+        packed_8888 dword;
+        dword._i = *(PN_uint32 *)pointer;
+        maybe_scale_color(dword._b[0], dword._b[1], dword._b[2]);
+      }
+      return _v3;
+      
+    case qpGeomVertexDataType::NT_float32:
+      {
+        PN_float32 *pi = (PN_float32 *)pointer;
+        _v3.set(pi[0], pi[1], pi[2]);
+      }
+      return _v3;
+    }
+  }
+
+  return _v3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::get_data4f
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const LVecBase4f &qpGeomVertexReader::Reader::
+get_data4f(const unsigned char *pointer) {
+  switch (_data_type->get_num_values()) {
+  case 1:
+    _v4.set(get_data1i(pointer), 0.0f, 0.0f, 0.0f);
+    return _v4;
+
+  case 2:
+    {
+      const LVecBase2f &v2 = get_data2f(pointer);
+      _v4.set(v2[0], v2[1], 0.0f, 0.0f);
+    }
+    return _v4;
+
+  case 3:
+    {
+      const LVecBase3f &v3 = get_data3f(pointer);
+      _v4.set(v3[0], v3[1], v3[2], 0.0f);
+    }
+    return _v4;
+
+  default:
+    switch (_data_type->get_numeric_type()) {
+    case qpGeomVertexDataType::NT_uint8:
+      maybe_scale_color(pointer[0], pointer[1], pointer[2], pointer[3]);
+      return _v4;
+      
+    case qpGeomVertexDataType::NT_uint16:
+      {
+        PN_uint16 *pi = (PN_uint16 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+      
+    case qpGeomVertexDataType::NT_packed_8888:
+      {
+        packed_8888 dword;
+        dword._i = *(PN_uint32 *)pointer;
+        maybe_scale_color(dword._b[0], dword._b[1], dword._b[2], dword._b[3]);
+      }
+      return _v4;
+      
+    case qpGeomVertexDataType::NT_float32:
+      {
+        PN_float32 *pi = (PN_float32 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+    }
+  }
+
+  return _v4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader::get_data1i
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexReader::Reader::
+get_data1i(const unsigned char *pointer) {
+  switch (_data_type->get_numeric_type()) {
+  case qpGeomVertexDataType::NT_uint8:
+    return *pointer;
+
+  case qpGeomVertexDataType::NT_uint16:
+    return *(PN_uint16 *)pointer;
+
+  case qpGeomVertexDataType::NT_packed_8888:
+    {
+      packed_8888 dword;
+      dword._i = *(PN_uint32 *)pointer;
+      return dword._b[0];
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_float32:
+    return (int)*(PN_float32 *)pointer;
+  }
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader_point::get_data4f
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const LVecBase4f &qpGeomVertexReader::Reader_point::
+get_data4f(const unsigned char *pointer) {
+  switch (_data_type->get_num_values()) {
+  case 1:
+    _v4.set(get_data1i(pointer), 0.0f, 0.0f, 1.0f);
+    return _v4;
+
+  case 2:
+    {
+      const LVecBase2f &v2 = get_data2f(pointer);
+      _v4.set(v2[0], v2[1], 0.0f, 1.0f);
+    }
+    return _v4;
+
+  case 3:
+    {
+      const LVecBase3f &v3 = get_data3f(pointer);
+      _v4.set(v3[0], v3[1], v3[2], 1.0f);
+    }
+    return _v4;
+
+  default:
+    switch (_data_type->get_numeric_type()) {
+    case qpGeomVertexDataType::NT_uint8:
+      maybe_scale_color(pointer[0], pointer[1], pointer[2], pointer[3]);
+      return _v4;
+      
+    case qpGeomVertexDataType::NT_uint16:
+      {
+        PN_uint16 *pi = (PN_uint16 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+      
+    case qpGeomVertexDataType::NT_packed_8888:
+      {
+        packed_8888 dword;
+        dword._i = *(PN_uint32 *)pointer;
+        maybe_scale_color(dword._b[0], dword._b[1], dword._b[2], dword._b[3]);
+      }
+      return _v4;
+      
+    case qpGeomVertexDataType::NT_float32:
+      {
+        PN_float32 *pi = (PN_float32 *)pointer;
+        _v4.set(pi[0], pi[1], pi[2], pi[3]);
+      }
+      return _v4;
+    }
+  }
+
+  return _v4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader_float_3::get_data3f
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const LVecBase3f &qpGeomVertexReader::Reader_float_3::
+get_data3f(const unsigned char *pointer) {
+  // We sneakily cast a float[3] array to an LVecBase3f reference,
+  // making all kinds of assumptions about how an LVecBase3f is
+  // stored.
+  return (LVecBase3f &)(float *)pointer;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexReader::Reader_uint16_1::get_data1i
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexReader::Reader_uint16_1::
+get_data1i(const unsigned char *pointer) {
+  return *(PN_uint16 *)pointer;
+}

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

@@ -0,0 +1,153 @@
+// Filename: qpgeomVertexReader.h
+// Created by:  drose (25Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef qpGEOMVERTEXREADER_H
+#define qpGEOMVERTEXREADER_H
+
+#include "pandabase.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomVertexDataType.h"
+#include "internalName.h"
+#include "luse.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomVertexReader
+// Description : This object provides a high-level interface for
+//               quickly reading a sequence of numeric values from a
+//               vertex table. 
+//
+//               It is particularly optimized for reading a column of
+//               data values for a series of vertices, without
+//               changing data types between each number.  Although
+//               you can use one GeomVertexReader to read one complete
+//               row at a time, by calling set_data_type() repeatedly
+//               for each vertex, it is faster to use a different
+//               GeomVertexReader for each data type.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomVertexReader {
+PUBLISHED:
+  INLINE qpGeomVertexReader(const qpGeomVertexData *vertex_data);
+  INLINE qpGeomVertexReader(const qpGeomVertexData *vertex_data,
+                            const string &name);
+  INLINE qpGeomVertexReader(const qpGeomVertexData *vertex_data,
+                            const InternalName *name);
+  INLINE ~qpGeomVertexReader();
+
+  INLINE const qpGeomVertexData *get_vertex_data() const;
+
+  INLINE void set_data_type(int data_type);
+  INLINE void set_data_type(const string &name);
+  INLINE void set_data_type(const InternalName *name);
+  void set_data_type(int array, const qpGeomVertexDataType *data_type);
+
+  INLINE int get_array() const;
+  INLINE const qpGeomVertexDataType *get_data_type() const;
+
+  INLINE void set_vertex(int vertex);
+
+  INLINE int get_start_vertex() const;
+  INLINE int get_read_vertex() const;
+
+  INLINE float get_data1f();
+  INLINE const LVecBase2f &get_data2f();
+  INLINE const LVecBase3f &get_data3f();
+  INLINE const LVecBase4f &get_data4f();
+
+  INLINE int get_data1i();
+
+private:
+  class Reader;
+
+  INLINE void set_pointer();
+  INLINE const unsigned char *inc_pointer();
+  Reader *make_reader() const;
+
+  CPT(qpGeomVertexData) _vertex_data;
+  int _array;
+  const qpGeomVertexDataType *_data_type;
+  int _stride;
+
+  CPTA_uchar _data;
+  const unsigned char *_pointer;
+
+  int _start_vertex;
+  int _read_vertex;
+
+  Reader *_reader;
+
+  // This union is handy for unpacking an NT_packed_8888 value.
+  typedef union {
+    unsigned char _b[4];
+    PN_uint32 _i;
+  } packed_8888;
+
+  // This nested class provides the implementation for unpacking data
+  // in a very general way, but also provides the hooks for
+  // implementing the common, very direct code paths (for instance,
+  // 3-component float32 to LVecBase3f) as quickly as possible.
+  class Reader {
+  public:
+    virtual ~Reader();
+    virtual float get_data1f(const unsigned char *pointer);
+    virtual const LVecBase2f &get_data2f(const unsigned char *pointer);
+    virtual const LVecBase3f &get_data3f(const unsigned char *pointer);
+    virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
+    virtual int get_data1i(const unsigned char *pointer);
+
+    INLINE float maybe_scale_color(unsigned int value);
+    INLINE void maybe_scale_color(unsigned int a, unsigned int b);
+    INLINE void maybe_scale_color(unsigned int a, unsigned int b,
+                                  unsigned int c);
+    INLINE void maybe_scale_color(unsigned int a, unsigned int b,
+                                  unsigned int c, unsigned int d);
+
+    const qpGeomVertexDataType *_data_type;
+    LVecBase2f _v2;
+    LVecBase3f _v3;
+    LVecBase4f _v4;
+  };
+
+  // This is a specialization on the generic Reader that handles
+  // points, which are special because the fourth component, if
+  // omitted, is 1.0.
+  class Reader_point : public Reader {
+  public:
+    virtual const LVecBase4f &get_data4f(const unsigned char *pointer);
+  };
+
+
+  // These are the specializations on the generic Reader that handle
+  // the direct code paths.
+
+  class Reader_float_3 : public Reader {
+  public:
+    virtual const LVecBase3f &get_data3f(const unsigned char *pointer);
+  };
+
+  class Reader_uint16_1 : public Reader {
+  public:
+    virtual int get_data1i(const unsigned char *pointer);
+  };
+};
+
+#include "qpgeomVertexReader.I"
+
+#endif