Browse Source

Add support for instance arrays via vertex attrib divisors

rdb 11 years ago
parent
commit
77c9e6cf6c

+ 16 - 0
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1359,6 +1359,22 @@ reset() {
   }
   }
 #endif
 #endif
 
 
+  _supports_vertex_attrib_divisor = false;
+#ifndef OPENGLES
+  if (is_at_least_gl_version(3, 3)) {
+    _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
+      get_extension_func("glVertexAttribDivisor");
+
+    _supports_vertex_attrib_divisor = true;
+
+  } else if (has_extension("GL_ARB_instanced_arrays")) {
+    _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
+      get_extension_func("glVertexAttribDivisorARB");
+
+    _supports_vertex_attrib_divisor = true;
+  }
+#endif
+
 #ifdef OPENGLES_2
 #ifdef OPENGLES_2
   // In OpenGL ES 2.x, FBO's are supported in the core.
   // In OpenGL ES 2.x, FBO's are supported in the core.
   _supports_framebuffer_object = true;
   _supports_framebuffer_object = true;

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

@@ -182,6 +182,7 @@ typedef void (APIENTRYP PFNGLVALIDATEPROGRAMPROC) (GLuint program);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBIPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
 typedef void (APIENTRYP PFNGLVERTEXATTRIBLPOINTERPROC) (GLuint index, GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (APIENTRYP PFNGLVERTEXATTRIBDIVISORPROC) (GLuint index, GLuint divisor);
 #endif  // OPENGLES_1
 #endif  // OPENGLES_1
 #ifndef OPENGLES
 #ifndef OPENGLES
 typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
 typedef void (APIENTRYP PFNGLGENSAMPLERSPROC) (GLsizei count, GLuint *samplers);
@@ -572,6 +573,8 @@ protected:
   bool _use_sender;
   bool _use_sender;
 #endif  // SUPPORT_IMMEDIATE_MODE
 #endif  // SUPPORT_IMMEDIATE_MODE
 
 
+  bool _supports_vertex_attrib_divisor;
+
   // Cache the data necessary to bind each particular light each
   // Cache the data necessary to bind each particular light each
   // frame, so if we bind a given light multiple times, we only have
   // frame, so if we bind a given light multiple times, we only have
   // to compute its data once.
   // to compute its data once.
@@ -785,6 +788,7 @@ public:
   PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
   PFNGLVERTEXATTRIBPOINTERPROC _glVertexAttribPointer;
   PFNGLVERTEXATTRIBIPOINTERPROC _glVertexAttribIPointer;
   PFNGLVERTEXATTRIBIPOINTERPROC _glVertexAttribIPointer;
   PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer;
   PFNGLVERTEXATTRIBLPOINTERPROC _glVertexAttribLPointer;
+  PFNGLVERTEXATTRIBDIVISORPROC _glVertexAttribDivisor;
 #endif  // OPENGLES_1
 #endif  // OPENGLES_1
 #ifndef OPENGLES
 #ifndef OPENGLES
   PFNGLGENSAMPLERSPROC _glGenSamplers;
   PFNGLGENSAMPLERSPROC _glGenSamplers;

+ 12 - 4
panda/src/glstuff/glShaderContext_src.cxx

@@ -998,6 +998,9 @@ disable_shader_vertex_arrays() {
   for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
   for (int i=0; i<(int)_shader->_var_spec.size(); i++) {
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     const Shader::ShaderVarSpec &bind = _shader->_var_spec[i];
     const GLint p = _glsl_parameter_map[bind._id._seqno];
     const GLint p = _glsl_parameter_map[bind._id._seqno];
+    if (_glgsg->_supports_vertex_attrib_divisor) {
+      _glgsg->_glVertexAttribDivisor(p, 0);
+    }
     _glgsg->_glDisableVertexAttribArray(p);
     _glgsg->_glDisableVertexAttribArray(p);
   }
   }
 
 
@@ -1052,10 +1055,10 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
       }
       }
       GLint p = _glsl_parameter_map[bind._id._seqno];
       GLint p = _glsl_parameter_map[bind._id._seqno];
 
 
-      int num_elements, element_stride;
+      int num_elements, element_stride, divisor;
       if (_glgsg->_data_reader->get_array_info(name, array_reader,
       if (_glgsg->_data_reader->get_array_info(name, array_reader,
                                                num_values, numeric_type,
                                                num_values, numeric_type,
-                                               start, stride,
+                                               start, stride, divisor,
                                                num_elements, element_stride)) {
                                                num_elements, element_stride)) {
         const unsigned char *client_pointer;
         const unsigned char *client_pointer;
         if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
         if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
@@ -1066,12 +1069,12 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
         for (int i = 0; i < num_elements; ++i) {
         for (int i = 0; i < num_elements; ++i) {
           _glgsg->_glEnableVertexAttribArray(p);
           _glgsg->_glEnableVertexAttribArray(p);
 
 
-  #ifndef OPENGLES
+#ifndef OPENGLES
           if (bind._integer) {
           if (bind._integer) {
             _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
             _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
                                             stride, client_pointer);
                                             stride, client_pointer);
           } else
           } else
-  #endif
+#endif
           if (numeric_type == GeomEnums::NT_packed_dabc) {
           if (numeric_type == GeomEnums::NT_packed_dabc) {
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
             _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
                                            GL_TRUE, stride, client_pointer);
                                            GL_TRUE, stride, client_pointer);
@@ -1079,6 +1082,11 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
             _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
             _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
                                            GL_TRUE, stride, client_pointer);
                                            GL_TRUE, stride, client_pointer);
           }
           }
+
+          if (_glgsg->_supports_vertex_attrib_divisor) {
+            _glgsg->_glVertexAttribDivisor(p, divisor);
+          }
+
           ++p;
           ++p;
           client_pointer += element_stride;
           client_pointer += element_stride;
         }
         }

+ 27 - 0
panda/src/gobj/geomVertexArrayFormat.I

@@ -106,6 +106,33 @@ set_pad_to(int pad_to) {
   _stride = ((_stride + _pad_to - 1) / _pad_to) * _pad_to;
   _stride = ((_stride + _pad_to - 1) / _pad_to) * _pad_to;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayFormat::get_divisor
+//       Access: Published
+//  Description: Returns the divisor attribute for the data in this
+//               array.  If 0, it contains per-vertex data.  If 1,
+//               it contains per-instance data.  If higher than 1,
+//               the read row is advanced for each n instances.
+////////////////////////////////////////////////////////////////////
+INLINE int GeomVertexArrayFormat::
+get_divisor() const {
+  return _divisor;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexArrayFormat::set_divisor
+//       Access: Published
+//  Description: Set this to 0 to indicate that this array contains
+//               per-vertex data, or to 1 to indicate that it
+//               contains per-instance data.  If higher than 1,
+//               the read row is advanced for each n instances.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexArrayFormat::
+set_divisor(int divisor) {
+  nassertv(divisor >= 0);
+  _divisor = divisor;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::get_total_bytes
 //     Function: GeomVertexArrayFormat::get_total_bytes
 //       Access: Published
 //       Access: Published

+ 37 - 21
panda/src/gobj/geomVertexArrayFormat.cxx

@@ -28,7 +28,7 @@ TypeHandle GeomVertexArrayFormat::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Constructor
 //     Function: GeomVertexArrayFormat::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 GeomVertexArrayFormat() :
 GeomVertexArrayFormat() :
@@ -36,6 +36,7 @@ GeomVertexArrayFormat() :
   _stride(0),
   _stride(0),
   _total_bytes(0),
   _total_bytes(0),
   _pad_to(1),
   _pad_to(1),
+  _divisor(0),
   _columns_unsorted(false)
   _columns_unsorted(false)
 {
 {
 }
 }
@@ -43,7 +44,7 @@ GeomVertexArrayFormat() :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Constructor
 //     Function: GeomVertexArrayFormat::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
@@ -53,6 +54,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
   _stride(0),
   _stride(0),
   _total_bytes(0),
   _total_bytes(0),
   _pad_to(1),
   _pad_to(1),
+  _divisor(0),
   _columns_unsorted(false)
   _columns_unsorted(false)
 {
 {
   add_column(name0, num_components0, numeric_type0, contents0);
   add_column(name0, num_components0, numeric_type0, contents0);
@@ -61,7 +63,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Constructor
 //     Function: GeomVertexArrayFormat::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
@@ -74,6 +76,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
   _stride(0),
   _stride(0),
   _total_bytes(0),
   _total_bytes(0),
   _pad_to(1),
   _pad_to(1),
+  _divisor(0),
   _columns_unsorted(false)
   _columns_unsorted(false)
 {
 {
   add_column(name0, num_components0, numeric_type0, contents0);
   add_column(name0, num_components0, numeric_type0, contents0);
@@ -83,7 +86,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Constructor
 //     Function: GeomVertexArrayFormat::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
@@ -99,6 +102,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
   _stride(0),
   _stride(0),
   _total_bytes(0),
   _total_bytes(0),
   _pad_to(1),
   _pad_to(1),
+  _divisor(0),
   _columns_unsorted(false)
   _columns_unsorted(false)
 {
 {
   add_column(name0, num_components0, numeric_type0, contents0);
   add_column(name0, num_components0, numeric_type0, contents0);
@@ -109,7 +113,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Constructor
 //     Function: GeomVertexArrayFormat::Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
 GeomVertexArrayFormat(InternalName *name0, int num_components0,
@@ -128,6 +132,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
   _stride(0),
   _stride(0),
   _total_bytes(0),
   _total_bytes(0),
   _pad_to(1),
   _pad_to(1),
+  _divisor(0),
   _columns_unsorted(false)
   _columns_unsorted(false)
 {
 {
   add_column(name0, num_components0, numeric_type0, contents0);
   add_column(name0, num_components0, numeric_type0, contents0);
@@ -139,7 +144,7 @@ GeomVertexArrayFormat(InternalName *name0, int num_components0,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Copy Constructor
 //     Function: GeomVertexArrayFormat::Copy Constructor
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
 GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
@@ -147,6 +152,7 @@ GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
   _stride(copy._stride),
   _stride(copy._stride),
   _total_bytes(copy._total_bytes),
   _total_bytes(copy._total_bytes),
   _pad_to(copy._pad_to),
   _pad_to(copy._pad_to),
+  _divisor(copy._divisor),
   _columns_unsorted(copy._columns_unsorted)
   _columns_unsorted(copy._columns_unsorted)
 {
 {
   Columns::const_iterator dti;
   Columns::const_iterator dti;
@@ -158,7 +164,7 @@ GeomVertexArrayFormat(const GeomVertexArrayFormat &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Copy Assignment Operator
 //     Function: GeomVertexArrayFormat::Copy Assignment Operator
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexArrayFormat::
 void GeomVertexArrayFormat::
 operator = (const GeomVertexArrayFormat &copy) {
 operator = (const GeomVertexArrayFormat &copy) {
@@ -166,6 +172,7 @@ operator = (const GeomVertexArrayFormat &copy) {
   _stride = copy._stride;
   _stride = copy._stride;
   _total_bytes = copy._total_bytes;
   _total_bytes = copy._total_bytes;
   _pad_to = copy._pad_to;
   _pad_to = copy._pad_to;
+  _divisor = copy._divisor;
 
 
   _columns.clear();
   _columns.clear();
   _columns_by_name.clear();
   _columns_by_name.clear();
@@ -175,11 +182,11 @@ operator = (const GeomVertexArrayFormat &copy) {
     add_column(*(*dti));
     add_column(*(*dti));
   }
   }
 }
 }
-  
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Destructor
 //     Function: GeomVertexArrayFormat::Destructor
 //       Access: Published, Virtual
 //       Access: Published, Virtual
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::
 GeomVertexArrayFormat::
 ~GeomVertexArrayFormat() {
 ~GeomVertexArrayFormat() {
@@ -228,15 +235,15 @@ unref() const {
 //               type.
 //               type.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomVertexArrayFormat::
 int GeomVertexArrayFormat::
-add_column(InternalName *name, int num_components, 
-           GeomVertexArrayFormat::NumericType numeric_type, 
+add_column(InternalName *name, int num_components,
+           GeomVertexArrayFormat::NumericType numeric_type,
            GeomVertexArrayFormat::Contents contents, int start,
            GeomVertexArrayFormat::Contents contents, int start,
            int column_alignment) {
            int column_alignment) {
   if (start < 0) {
   if (start < 0) {
     start = _total_bytes;
     start = _total_bytes;
   }
   }
 
 
-  return add_column(GeomVertexColumn(name, num_components, numeric_type, contents, 
+  return add_column(GeomVertexColumn(name, num_components, numeric_type, contents,
                                      start, column_alignment));
                                      start, column_alignment));
 }
 }
 
 
@@ -500,7 +507,7 @@ count_unused_space() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::output
 //     Function: GeomVertexArrayFormat::output
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexArrayFormat::
 void GeomVertexArrayFormat::
 output(ostream &out) const {
 output(ostream &out) const {
@@ -526,7 +533,7 @@ output(ostream &out) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::write
 //     Function: GeomVertexArrayFormat::write
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexArrayFormat::
 void GeomVertexArrayFormat::
 write(ostream &out, int indent_level) const {
 write(ostream &out, int indent_level) const {
@@ -537,7 +544,7 @@ write(ostream &out, int indent_level) const {
   for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
   for (ci = _columns.begin(); ci != _columns.end(); ++ci) {
     const GeomVertexColumn *column = (*ci);
     const GeomVertexColumn *column = (*ci);
     indent(out, indent_level + 2)
     indent(out, indent_level + 2)
-      << *column 
+      << *column
       << " " << column->get_numeric_type()
       << " " << column->get_numeric_type()
       << " " << column->get_contents()
       << " " << column->get_contents()
       << " start at " << column->get_start() << "\n";
       << " start at " << column->get_start() << "\n";
@@ -547,7 +554,7 @@ write(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::write_with_data
 //     Function: GeomVertexArrayFormat::write_with_data
 //       Access: Published
 //       Access: Published
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GeomVertexArrayFormat::
 void GeomVertexArrayFormat::
 write_with_data(ostream &out, int indent_level,
 write_with_data(ostream &out, int indent_level,
@@ -568,7 +575,7 @@ write_with_data(ostream &out, int indent_level,
       reader.set_column(0, column);
       reader.set_column(0, column);
       const LVecBase4f &d = reader.get_data4f();
       const LVecBase4f &d = reader.get_data4f();
 
 
-      indent(out, indent_level + 2) 
+      indent(out, indent_level + 2)
         << *column->get_name();
         << *column->get_name();
       for (int v = 0; v < num_values; v++) {
       for (int v = 0; v < num_values; v++) {
         out << " " << d[v];
         out << " " << d[v];
@@ -658,7 +665,7 @@ get_format_string(bool pad) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::compare_to
 //     Function: GeomVertexArrayFormat::compare_to
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int GeomVertexArrayFormat::
 int GeomVertexArrayFormat::
 compare_to(const GeomVertexArrayFormat &other) const {
 compare_to(const GeomVertexArrayFormat &other) const {
@@ -671,6 +678,9 @@ compare_to(const GeomVertexArrayFormat &other) const {
   if (_pad_to != other._pad_to) {
   if (_pad_to != other._pad_to) {
     return _pad_to - other._pad_to;
     return _pad_to - other._pad_to;
   }
   }
+  if (_divisor != other._divisor) {
+    return _divisor - other._divisor;
+  }
   if (_columns.size() != other._columns.size()) {
   if (_columns.size() != other._columns.size()) {
     return (int)_columns.size() - (int)other._columns.size();
     return (int)_columns.size() - (int)other._columns.size();
   }
   }
@@ -720,7 +730,7 @@ do_register() {
   nassertv(!_is_registered);
   nassertv(!_is_registered);
   _is_registered = true;
   _is_registered = true;
 }
 }
- 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::do_unregister
 //     Function: GeomVertexArrayFormat::do_unregister
 //       Access: Private
 //       Access: Private
@@ -756,6 +766,7 @@ write_datagram(BamWriter *manager, Datagram &dg) {
   dg.add_uint16(_stride);
   dg.add_uint16(_stride);
   dg.add_uint16(_total_bytes);
   dg.add_uint16(_total_bytes);
   dg.add_uint8(_pad_to);
   dg.add_uint8(_pad_to);
+  dg.add_uint16(_divisor);
 
 
   consider_sort_columns();
   consider_sort_columns();
 
 
@@ -845,6 +856,11 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   _stride = scan.get_uint16();
   _stride = scan.get_uint16();
   _total_bytes = scan.get_uint16();
   _total_bytes = scan.get_uint16();
   _pad_to = scan.get_uint8();
   _pad_to = scan.get_uint8();
+  if (manager->get_file_minor_ver() > 36) {
+    _divisor = scan.get_uint16();
+  } else {
+    _divisor = 0;
+  }
 
 
   int num_columns = scan.get_uint16();
   int num_columns = scan.get_uint16();
   _columns.reserve(num_columns);
   _columns.reserve(num_columns);
@@ -859,7 +875,7 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexArrayFormat::Registry::Constructor
 //     Function: GeomVertexArrayFormat::Registry::Constructor
 //       Access: Public
 //       Access: Public
-//  Description: 
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomVertexArrayFormat::Registry::
 GeomVertexArrayFormat::Registry::
 Registry() {
 Registry() {
@@ -890,7 +906,7 @@ register_format(GeomVertexArrayFormat *format) {
   // a zero reference count and is not added into the map below, it
   // a zero reference count and is not added into the map below, it
   // will be automatically deleted when this function returns.
   // will be automatically deleted when this function returns.
   PT(GeomVertexArrayFormat) pt_format = format;
   PT(GeomVertexArrayFormat) pt_format = format;
-  
+
   GeomVertexArrayFormat *new_format;
   GeomVertexArrayFormat *new_format;
   {
   {
     LightMutexHolder holder(_lock);
     LightMutexHolder holder(_lock);

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

@@ -88,6 +88,9 @@ PUBLISHED:
   INLINE int get_pad_to() const;
   INLINE int get_pad_to() const;
   INLINE void set_pad_to(int pad_to);
   INLINE void set_pad_to(int pad_to);
 
 
+  INLINE int get_divisor() const;
+  INLINE void set_divisor(int divisor);
+
   INLINE int get_total_bytes() const;
   INLINE int get_total_bytes() const;
 
 
   int add_column(InternalName *name, int num_components,
   int add_column(InternalName *name, int num_components,
@@ -135,6 +138,7 @@ private:
   int _stride;
   int _stride;
   int _total_bytes;
   int _total_bytes;
   int _pad_to;
   int _pad_to;
+  int _divisor;
 
 
   typedef pvector<GeomVertexColumn *> Columns;
   typedef pvector<GeomVertexColumn *> Columns;
   Columns _columns;
   Columns _columns;

+ 11 - 12
panda/src/gobj/geomVertexData.I

@@ -98,12 +98,10 @@ get_num_rows() const {
 //               was changed, false if the object already contained n
 //               was changed, false if the object already contained n
 //               rows (or if there was some error).
 //               rows (or if there was some error).
 //
 //
-//               Although this method is Published, application code
-//               only very rarely has any need to call it.  Instead,
-//               you should use the GeomVertexWriter to build up the
-//               rows in a GeomVertexData object automatically,
-//               without need to explicitly set the number of
-//               rows.
+//               This can be used when you know exactly how many
+//               rows you will be needing.  It is faster than
+//               reserve_num_rows().  Also see unclean_set_num_rows()
+//               if you are planning to fill in all the data yourself.
 //
 //
 //               Don't call this in a downstream thread unless you
 //               Don't call this in a downstream thread unless you
 //               don't mind it blowing away other changes you might
 //               don't mind it blowing away other changes you might
@@ -129,12 +127,9 @@ set_num_rows(int n) {
 //               anyway; it provides a tiny performance boost over
 //               anyway; it provides a tiny performance boost over
 //               set_num_rows().
 //               set_num_rows().
 //
 //
-//               Although this method is Published, application code
-//               only very rarely has any need to call it.  Instead,
-//               you should use the GeomVertexWriter to build up the
-//               rows in a GeomVertexData object automatically,
-//               without need to explicitly set the number of
-//               rows.
+//               This can be used when you know exactly how many
+//               rows you will be needing.  It is faster than
+//               reserve_num_rows().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexData::
 INLINE bool GeomVertexData::
 unclean_set_num_rows(int n) {
 unclean_set_num_rows(int n) {
@@ -152,6 +147,10 @@ unclean_set_num_rows(int n) {
 //               This is a performance optimization only; it is
 //               This is a performance optimization only; it is
 //               especially useful when you know ahead of time that
 //               especially useful when you know ahead of time that
 //               you will be adding n rows to the data.
 //               you will be adding n rows to the data.
+//
+//               If you know exactly how many rows you will be
+//               needing, it is significantly faster to use
+//               set_num_rows() or unclean_set_num_rows() instead.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool GeomVertexData::
 INLINE bool GeomVertexData::
 reserve_num_rows(int n) {
 reserve_num_rows(int n) {

+ 2 - 1
panda/src/gobj/geomVertexData.cxx

@@ -2368,7 +2368,7 @@ get_array_info(const InternalName *name,
                const GeomVertexArrayDataHandle *&array_reader,
                const GeomVertexArrayDataHandle *&array_reader,
                int &num_values,
                int &num_values,
                GeomVertexDataPipelineReader::NumericType &numeric_type,
                GeomVertexDataPipelineReader::NumericType &numeric_type,
-               int &start, int &stride,
+               int &start, int &stride, int &divisor,
                int &num_elements, int &element_stride) const {
                int &num_elements, int &element_stride) const {
   nassertr(_got_array_readers, false);
   nassertr(_got_array_readers, false);
   int array_index;
   int array_index;
@@ -2379,6 +2379,7 @@ get_array_info(const InternalName *name,
     numeric_type = column->get_numeric_type();
     numeric_type = column->get_numeric_type();
     start = column->get_start();
     start = column->get_start();
     stride = _cdata->_format->get_array(array_index)->get_stride();
     stride = _cdata->_format->get_array(array_index)->get_stride();
+    divisor = _cdata->_format->get_array(array_index)->get_divisor();
     num_elements = column->get_num_elements();
     num_elements = column->get_num_elements();
     element_stride = column->get_element_stride();
     element_stride = column->get_element_stride();
     return true;
     return true;

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

@@ -453,7 +453,7 @@ public:
   bool get_array_info(const InternalName *name,
   bool get_array_info(const InternalName *name,
                       const GeomVertexArrayDataHandle *&array_reader,
                       const GeomVertexArrayDataHandle *&array_reader,
                       int &num_values, NumericType &numeric_type,
                       int &num_values, NumericType &numeric_type,
-                      int &start, int &stride,
+                      int &start, int &stride, int &divisor,
                       int &num_elements, int &element_stride) const;
                       int &num_elements, int &element_stride) const;
 
 
   INLINE bool has_vertex() const;
   INLINE bool has_vertex() const;

+ 2 - 1
panda/src/putil/bam.h

@@ -33,7 +33,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
 
 static const unsigned short _bam_first_minor_ver = 14;
 static const unsigned short _bam_first_minor_ver = 14;
-static const unsigned short _bam_minor_ver = 36;
+static const unsigned short _bam_minor_ver = 37;
 // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
 // Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
 // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
 // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
 // Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
@@ -57,5 +57,6 @@ static const unsigned short _bam_minor_ver = 36;
 // Bumped to minor version 34 on 9/16/14 to add ScissorAttrib::_off.
 // Bumped to minor version 34 on 9/16/14 to add ScissorAttrib::_off.
 // Bumped to minor version 35 on 12/3/14 to change StencilAttrib.
 // Bumped to minor version 35 on 12/3/14 to change StencilAttrib.
 // Bumped to minor version 36 on 12/9/14 to add samplers and lod settings.
 // Bumped to minor version 36 on 12/9/14 to add samplers and lod settings.
+// Bumped to minor version 37 on 1/22/15 to add GeomVertexArrayFormat::_divisor.
 
 
 #endif
 #endif