瀏覽代碼

Support vertex attributes with matrix type

rdb 11 年之前
父節點
當前提交
a7f7d54f10

+ 26 - 19
panda/src/glstuff/glShaderContext_src.cxx

@@ -1050,30 +1050,37 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
           name = name->append(texname->get_basename());
         }
       }
-      const GLint p = _glsl_parameter_map[bind._id._seqno];
+      GLint p = _glsl_parameter_map[bind._id._seqno];
 
-      if (_glgsg->_data_reader->get_array_info(name,
-                                               array_reader, num_values, numeric_type,
-                                               start, stride)) {
+      int num_elements, element_stride;
+      if (_glgsg->_data_reader->get_array_info(name, array_reader,
+                                               num_values, numeric_type,
+                                               start, stride,
+                                               num_elements, element_stride)) {
         const unsigned char *client_pointer;
         if (!_glgsg->setup_array_data(client_pointer, array_reader, force)) {
           return false;
         }
-
-        _glgsg->_glEnableVertexAttribArray(p);
-
-#ifndef OPENGLES
-        if (bind._integer) {
-          _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
-                                          stride, client_pointer + start);
-        } else
-#endif
-        if (numeric_type == GeomEnums::NT_packed_dabc) {
-          _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
-                                         GL_TRUE, stride, client_pointer + start);
-        } else {
-          _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
-                                         GL_TRUE, stride, client_pointer + start);
+        client_pointer += start;
+
+        for (int i = 0; i < num_elements; ++i) {
+          _glgsg->_glEnableVertexAttribArray(p);
+
+  #ifndef OPENGLES
+          if (bind._integer) {
+            _glgsg->_glVertexAttribIPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
+                                            stride, client_pointer);
+          } else
+  #endif
+          if (numeric_type == GeomEnums::NT_packed_dabc) {
+            _glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
+                                           GL_TRUE, stride, client_pointer);
+          } else {
+            _glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
+                                           GL_TRUE, stride, client_pointer);
+          }
+          ++p;
+          client_pointer += element_stride;
         }
       } else {
         _glgsg->_glDisableVertexAttribArray(p);

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

@@ -202,6 +202,10 @@ PUBLISHED:
     C_color,        // 3- or 4-component color, ordered R, G, B, [A]
     C_index,        // An index value into some other table
     C_morph_delta,  // A delta from some base value, defining a blend shape
+
+    // A transformation matrix.  This is typically three or four
+    // columns, but we pretend it's only one for convenience.
+    C_matrix,
   };
 
   // The type of animation data that is represented by a particular

+ 23 - 0
panda/src/gobj/geomVertexColumn.I

@@ -116,6 +116,17 @@ get_num_values() const {
   return _num_values;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexColumn::get_num_elements
+//       Access: Published
+//  Description: Returns the number of times this column is repeated.
+//               This is usually 1, except for matrices.
+////////////////////////////////////////////////////////////////////
+INLINE int GeomVertexColumn::
+get_num_elements() const {
+  return _num_elements;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexColumn::get_numeric_type
 //       Access: Published
@@ -165,6 +176,18 @@ get_column_alignment() const {
   return _column_alignment;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexColumn::get_element_stride
+//       Access: Published
+//  Description: This value is only relevant for matrix types.
+//               Returns the number of bytes to add to access the
+//               next row of the matrix.
+////////////////////////////////////////////////////////////////////
+INLINE int GeomVertexColumn::
+get_element_stride() const {
+  return _element_stride;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexColumn::get_component_bytes
 //       Access: Published

+ 7 - 2
panda/src/gobj/geomVertexColumn.cxx

@@ -168,6 +168,7 @@ setup() {
   nassertv(_num_components > 0 && _start >= 0);
 
   _num_values = _num_components;
+  _num_elements = 1;
 
   if (_numeric_type == NT_stdfloat) {
     if (vertices_float64) {
@@ -209,6 +210,10 @@ setup() {
     break;
   }
 
+  if (_contents == C_matrix) {
+    _num_elements = _num_components;
+  }
+
   if (_column_alignment < 1) {
     // The default column alignment is to align to the individual
     // numeric components, or to vertex_column_alignment, whichever is
@@ -219,7 +224,8 @@ setup() {
   // Enforce the column alignment requirements on the _start byte.
   _start = ((_start + _column_alignment - 1) / _column_alignment) * _column_alignment;
 
-  _total_bytes = _component_bytes * _num_components;
+  _element_stride = _component_bytes * _num_components;
+  _total_bytes = _element_stride * _num_elements;
 
   if (_packer != NULL) {
     delete _packer;
@@ -334,7 +340,6 @@ make_packer() const {
       break;
     }
     return new Packer_color;
-
   default:
     // Otherwise, we just read it as a generic value.
     switch (get_numeric_type()) {

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

@@ -52,10 +52,12 @@ PUBLISHED:
   INLINE InternalName *get_name() const;
   INLINE int get_num_components() const;
   INLINE int get_num_values() const;
+  INLINE int get_num_elements() const;
   INLINE NumericType get_numeric_type() const;
   INLINE Contents get_contents() const;
   INLINE int get_start() const;
   INLINE int get_column_alignment() const;
+  INLINE int get_element_stride() const;
   INLINE int get_component_bytes() const;
   INLINE int get_total_bytes() const;
   INLINE bool has_homogeneous_coord() const;
@@ -96,10 +98,12 @@ private:
   PT(InternalName) _name;
   int _num_components;
   int _num_values;
+  int _num_elements;
   NumericType _numeric_type;
   Contents _contents;
   int _start;
   int _column_alignment;
+  int _element_stride;
   int _component_bytes;
   int _total_bytes;
   Packer *_packer;

+ 28 - 0
panda/src/gobj/geomVertexData.cxx

@@ -2358,6 +2358,34 @@ get_array_info(const InternalName *name,
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexDataPipelineReader::get_array_info
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+bool GeomVertexDataPipelineReader::
+get_array_info(const InternalName *name,
+               const GeomVertexArrayDataHandle *&array_reader,
+               int &num_values,
+               GeomVertexDataPipelineReader::NumericType &numeric_type,
+               int &start, int &stride,
+               int &num_elements, int &element_stride) const {
+  nassertr(_got_array_readers, false);
+  int array_index;
+  const GeomVertexColumn *column;
+  if (_cdata->_format->get_array_info(name, array_index, column)) {
+    array_reader = _array_readers[array_index];
+    num_values = column->get_num_values();
+    numeric_type = column->get_numeric_type();
+    start = column->get_start();
+    stride = _cdata->_format->get_array(array_index)->get_stride();
+    num_elements = column->get_num_elements();
+    element_stride = column->get_element_stride();
+    return true;
+  }
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexDataPipelineReader::get_vertex_info
 //       Access: Public

+ 6 - 0
panda/src/gobj/geomVertexData.h

@@ -450,6 +450,12 @@ public:
                       int &num_values, NumericType &numeric_type,
                       int &start, int &stride) const;
 
+  bool get_array_info(const InternalName *name,
+                      const GeomVertexArrayDataHandle *&array_reader,
+                      int &num_values, NumericType &numeric_type,
+                      int &start, int &stride,
+                      int &num_elements, int &element_stride) const;
+
   INLINE bool has_vertex() const;
   INLINE bool is_vertex_transformed() const;
   bool get_vertex_info(const GeomVertexArrayDataHandle *&array_reader,

+ 5 - 4
panda/src/gobj/geomVertexFormat.h

@@ -138,10 +138,11 @@ PUBLISHED:
   INLINE static const GeomVertexFormat *get_v3t2();
   INLINE static const GeomVertexFormat *get_v3n3t2();
 
-  // These formats, with the DirectX-style packed color, are not
-  // supported directly by OpenGL.  If you use them, the
-  // GLGraphicsStateGuardian will automatically convert to OpenGL
-  // form (with a small runtime overhead).
+  // These formats, with the DirectX-style packed color, may not be
+  // supported directly by OpenGL.  If you use them and the driver
+  // does not support them, the GLGraphicsStateGuardian will
+  // automatically convert to native OpenGL form (with a small
+  // runtime overhead).
   INLINE static const GeomVertexFormat *get_v3cp();
   INLINE static const GeomVertexFormat *get_v3cpt2();
   INLINE static const GeomVertexFormat *get_v3n3cp();

+ 146 - 0
panda/src/gobj/geomVertexReader.I

@@ -524,6 +524,62 @@ get_data4f() {
   return _packer->get_data4f(inc_pointer());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexReader::get_matrix3f
+//       Access: Published
+//  Description: Returns the 3-by-3 matrix associated with the read
+//               row and advances the read row.  This is a special
+//               method that only works when the column in question
+//               contains a matrix of an appropriate size.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix3f GeomVertexReader::
+get_matrix3f() {
+  nassertr(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() >= 3,
+           LMatrix3f::ident_mat());
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  const unsigned char *pointer = inc_pointer();
+
+  LMatrix3f mat;
+  mat.set_row(0, _packer->get_data3f(pointer));
+  pointer += col_stride;
+  mat.set_row(1, _packer->get_data3f(pointer));
+  pointer += col_stride;
+  mat.set_row(2, _packer->get_data3f(pointer));
+  return mat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexReader::get_matrix4f
+//       Access: Published
+//  Description: Returns the 4-by-4 matrix associated with the read
+//               row and advances the read row.  This is a special
+//               method that only works when the column in question
+//               contains a matrix of an appropriate size.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix4f GeomVertexReader::
+get_matrix4f() {
+  nassertr(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() >= 4,
+           LMatrix4f::ident_mat());
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  const unsigned char *pointer = inc_pointer();
+
+  LMatrix4f mat;
+  mat.set_row(0, _packer->get_data4f(pointer));
+  pointer += col_stride;
+  mat.set_row(1, _packer->get_data4f(pointer));
+  pointer += col_stride;
+  mat.set_row(2, _packer->get_data4f(pointer));
+  pointer += col_stride;
+  mat.set_row(3, _packer->get_data4f(pointer));
+  return mat;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexReader::get_data1d
 //       Access: Published
@@ -576,6 +632,62 @@ get_data4d() {
   return _packer->get_data4d(inc_pointer());
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexReader::get_matrix3d
+//       Access: Published
+//  Description: Returns the 3-by-3 matrix associated with the read
+//               row and advances the read row.  This is a special
+//               method that only works when the column in question
+//               contains a matrix of an appropriate size.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix3d GeomVertexReader::
+get_matrix3d() {
+  nassertr(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() >= 3,
+           LMatrix3d::ident_mat());
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  const unsigned char *pointer = inc_pointer();
+
+  LMatrix3d mat;
+  mat.set_row(0, _packer->get_data3d(pointer));
+  pointer += col_stride;
+  mat.set_row(1, _packer->get_data3d(pointer));
+  pointer += col_stride;
+  mat.set_row(2, _packer->get_data3d(pointer));
+  return mat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexReader::get_matrix4d
+//       Access: Published
+//  Description: Returns the 4-by-4 matrix associated with the read
+//               row and advances the read row.  This is a special
+//               method that only works when the column in question
+//               contains a matrix of an appropriate size.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix4d GeomVertexReader::
+get_matrix4d() {
+  nassertr(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() >= 4,
+           LMatrix4d::ident_mat());
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  const unsigned char *pointer = inc_pointer();
+
+  LMatrix4d mat;
+  mat.set_row(0, _packer->get_data4d(pointer));
+  pointer += col_stride;
+  mat.set_row(1, _packer->get_data4d(pointer));
+  pointer += col_stride;
+  mat.set_row(2, _packer->get_data4d(pointer));
+  pointer += col_stride;
+  mat.set_row(3, _packer->get_data4d(pointer));
+  return mat;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexReader::get_data1
 //       Access: Published
@@ -640,6 +752,40 @@ get_data4() {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexReader::get_matrix3
+//       Access: Published
+//  Description: Returns the 3-by-3 matrix associated with the read
+//               row and advances the read row.  This is a special
+//               method that only works when the column in question
+//               contains a matrix of an appropriate size.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix3 GeomVertexReader::
+get_matrix3() {
+#ifndef STDFLOAT_DOUBLE
+  return get_matrix3f();
+#else
+  return get_matrix3d();
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexReader::get_matrix4
+//       Access: Published
+//  Description: Returns the 4-by-4 matrix associated with the read
+//               row and advances the read row.  This is a special
+//               method that only works when the column in question
+//               contains a matrix of an appropriate size.
+////////////////////////////////////////////////////////////////////
+INLINE LMatrix4 GeomVertexReader::
+get_matrix4() {
+#ifndef STDFLOAT_DOUBLE
+  return get_matrix4f();
+#else
+  return get_matrix4d();
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexReader::get_data1i
 //       Access: Published

+ 6 - 0
panda/src/gobj/geomVertexReader.h

@@ -110,16 +110,22 @@ PUBLISHED:
   INLINE const LVecBase2f &get_data2f();
   INLINE const LVecBase3f &get_data3f();
   INLINE const LVecBase4f &get_data4f();
+  INLINE LMatrix3f get_matrix3f();
+  INLINE LMatrix4f get_matrix4f();
 
   INLINE double get_data1d();
   INLINE const LVecBase2d &get_data2d();
   INLINE const LVecBase3d &get_data3d();
   INLINE const LVecBase4d &get_data4d();
+  INLINE LMatrix3d get_matrix3d();
+  INLINE LMatrix4d get_matrix4d();
 
   INLINE PN_stdfloat get_data1();
   INLINE const LVecBase2 &get_data2();
   INLINE const LVecBase3 &get_data3();
   INLINE const LVecBase4 &get_data4();
+  INLINE LMatrix3 get_matrix3();
+  INLINE LMatrix4 get_matrix4();
 
   INLINE int get_data1i();
   INLINE const LVecBase2i &get_data2i();

+ 292 - 0
panda/src/gobj/geomVertexWriter.I

@@ -538,6 +538,60 @@ set_data4f(const LVecBase4f &data) {
   _packer->set_data4f(inc_pointer(), data);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::set_matrix3f
+//       Access: Published
+//  Description: Sets the write row to a 3-by-3 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               It is an error for the write row to advance past
+//               the end of data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+set_matrix3f(const LMatrix3f &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 3);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_pointer();
+
+  _packer->set_data3f(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data3f(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data3f(pointer, mat.get_row(2));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::set_matrix4f
+//       Access: Published
+//  Description: Sets the write row to a 4-by-4 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               It is an error for the write row to advance past
+//               the end of data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+set_matrix4f(const LMatrix4f &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 4);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_pointer();
+
+  _packer->set_data4f(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data4f(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data4f(pointer, mat.get_row(2));
+  pointer += col_stride;
+  _packer->set_data4f(pointer, mat.get_row(3));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::set_data1d
 //       Access: Published
@@ -640,6 +694,60 @@ set_data4d(const LVecBase4d &data) {
   _packer->set_data4d(inc_pointer(), data);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::set_matrix3d
+//       Access: Published
+//  Description: Sets the write row to a 3-by-3 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               It is an error for the write row to advance past
+//               the end of data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+set_matrix3d(const LMatrix3d &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 3);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_pointer();
+
+  _packer->set_data3d(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data3d(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data3d(pointer, mat.get_row(2));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::set_matrix4d
+//       Access: Published
+//  Description: Sets the write row to a 4-by-4 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               It is an error for the write row to advance past
+//               the end of data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+set_matrix4d(const LMatrix4d &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 4);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_pointer();
+
+  _packer->set_data4d(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data4d(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data4d(pointer, mat.get_row(2));
+  pointer += col_stride;
+  _packer->set_data4d(pointer, mat.get_row(3));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::set_data1
 //       Access: Published
@@ -766,6 +874,44 @@ set_data4(const LVecBase4 &data) {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::set_matrix3
+//       Access: Published
+//  Description: Sets the write row to a 3-by-3 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               It is an error for the write row to advance past
+//               the end of data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+set_matrix3(const LMatrix3 &mat) {
+#ifndef STDFLOAT_DOUBLE
+  set_matrix3f(mat);
+#else
+  set_matrix3d(mat);
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::set_matrix4
+//       Access: Published
+//  Description: Sets the write row to a 4-by-4 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               It is an error for the write row to advance past
+//               the end of data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+set_matrix4(const LMatrix4 &mat) {
+#ifndef STDFLOAT_DOUBLE
+  set_matrix4f(mat);
+#else
+  set_matrix4d(mat);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::set_data1i
 //       Access: Published
@@ -1012,6 +1158,60 @@ add_data4f(const LVecBase4f &data) {
   _packer->set_data4f(inc_add_pointer(), data);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::add_matrix3f
+//       Access: Published
+//  Description: Sets the write row to a 3-by-3 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               If the write row advances past the end of data,
+//               implicitly adds a new row to the data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+add_matrix3f(const LMatrix3f &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 3);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_add_pointer();
+
+  _packer->set_data3f(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data3f(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data3f(pointer, mat.get_row(2));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::add_matrix4f
+//       Access: Published
+//  Description: Sets the write row to a 4-by-4 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               If the write row advances past the end of data,
+//               implicitly adds a new row to the data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+add_matrix4f(const LMatrix4f &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 4);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_add_pointer();
+
+  _packer->set_data4f(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data4f(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data4f(pointer, mat.get_row(2));
+  pointer += col_stride;
+  _packer->set_data4f(pointer, mat.get_row(3));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::add_data1d
 //       Access: Published
@@ -1114,6 +1314,60 @@ add_data4d(const LVecBase4d &data) {
   _packer->set_data4d(inc_add_pointer(), data);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::add_matrix3d
+//       Access: Published
+//  Description: Sets the write row to a 3-by-3 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               If the write row advances past the end of data,
+//               implicitly adds a new row to the data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+add_matrix3d(const LMatrix3d &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 3);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_add_pointer();
+
+  _packer->set_data3d(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data3d(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data3d(pointer, mat.get_row(2));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::add_matrix4d
+//       Access: Published
+//  Description: Sets the write row to a 4-by-4 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               If the write row advances past the end of data,
+//               implicitly adds a new row to the data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+add_matrix4d(const LMatrix4d &mat) {
+  nassertv(has_column() &&
+           _packer->_column->get_contents() == C_matrix &&
+           _packer->_column->get_num_elements() == 4);
+
+  size_t col_stride = _packer->_column->get_element_stride();
+  unsigned char *pointer = inc_add_pointer();
+
+  _packer->set_data4d(pointer, mat.get_row(0));
+  pointer += col_stride;
+  _packer->set_data4d(pointer, mat.get_row(1));
+  pointer += col_stride;
+  _packer->set_data4d(pointer, mat.get_row(2));
+  pointer += col_stride;
+  _packer->set_data4d(pointer, mat.get_row(3));
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::add_data1
 //       Access: Published
@@ -1240,6 +1494,44 @@ add_data4(const LVecBase4 &data) {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::add_matrix3
+//       Access: Published
+//  Description: Sets the write row to a 3-by-3 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               If the write row advances past the end of data,
+//               implicitly adds a new row to the data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+add_matrix3(const LMatrix3 &mat) {
+#ifndef STDFLOAT_DOUBLE
+  add_matrix3f(mat);
+#else
+  add_matrix3d(mat);
+#endif
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GeomVertexWriter::add_matrix4
+//       Access: Published
+//  Description: Sets the write row to a 4-by-4 matrix, and advances
+//               the write row.  This is a special method that can
+//               only be used on matrix columns.
+//
+//               If the write row advances past the end of data,
+//               implicitly adds a new row to the data.
+////////////////////////////////////////////////////////////////////
+INLINE void GeomVertexWriter::
+add_matrix4(const LMatrix4 &mat) {
+#ifndef STDFLOAT_DOUBLE
+  add_matrix4f(mat);
+#else
+  add_matrix4d(mat);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomVertexWriter::add_data1i
 //       Access: Published

+ 12 - 0
panda/src/gobj/geomVertexWriter.h

@@ -123,6 +123,8 @@ PUBLISHED:
   INLINE void set_data3f(const LVecBase3f &data);
   INLINE void set_data4f(float x, float y, float z, float w);
   INLINE void set_data4f(const LVecBase4f &data);
+  INLINE void set_matrix3f(const LMatrix3f &mat);
+  INLINE void set_matrix4f(const LMatrix4f &mat);
 
   INLINE void set_data1d(double data);
   INLINE void set_data2d(double x, double y);
@@ -131,6 +133,8 @@ PUBLISHED:
   INLINE void set_data3d(const LVecBase3d &data);
   INLINE void set_data4d(double x, double y, double z, double w);
   INLINE void set_data4d(const LVecBase4d &data);
+  INLINE void set_matrix3d(const LMatrix3d &mat);
+  INLINE void set_matrix4d(const LMatrix4d &mat);
 
   INLINE void set_data1(PN_stdfloat data);
   INLINE void set_data2(PN_stdfloat x, PN_stdfloat y);
@@ -139,6 +143,8 @@ PUBLISHED:
   INLINE void set_data3(const LVecBase3 &data);
   INLINE void set_data4(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat w);
   INLINE void set_data4(const LVecBase4 &data);
+  INLINE void set_matrix3(const LMatrix3 &mat);
+  INLINE void set_matrix4(const LMatrix4 &mat);
 
   INLINE void set_data1i(int data);
   INLINE void set_data2i(int a, int b);
@@ -158,6 +164,8 @@ PUBLISHED:
   INLINE void add_data3f(const LVecBase3f &data);
   INLINE void add_data4f(float x, float y, float z, float w);
   INLINE void add_data4f(const LVecBase4f &data);
+  INLINE void add_matrix3f(const LMatrix3f &mat);
+  INLINE void add_matrix4f(const LMatrix4f &mat);
 
   INLINE void add_data1d(double data);
   INLINE void add_data2d(double x, double y);
@@ -166,6 +174,8 @@ PUBLISHED:
   INLINE void add_data3d(const LVecBase3d &data);
   INLINE void add_data4d(double x, double y, double z, double w);
   INLINE void add_data4d(const LVecBase4d &data);
+  INLINE void add_matrix3d(const LMatrix3d &mat);
+  INLINE void add_matrix4d(const LMatrix4d &mat);
 
   INLINE void add_data1(PN_stdfloat data);
   INLINE void add_data2(PN_stdfloat x, PN_stdfloat y);
@@ -174,6 +184,8 @@ PUBLISHED:
   INLINE void add_data3(const LVecBase3 &data);
   INLINE void add_data4(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z, PN_stdfloat w);
   INLINE void add_data4(const LVecBase4 &data);
+  INLINE void add_matrix3(const LMatrix3 &mat);
+  INLINE void add_matrix4(const LMatrix4 &mat);
 
   INLINE void add_data1i(int data);
   INLINE void add_data2i(int a, int b);