Browse Source

initial checkin of experimental Geom rewrite--preliminary

David Rose 21 years ago
parent
commit
c975b7cd49
89 changed files with 8033 additions and 533 deletions
  1. 2 2
      panda/src/builder/builderBucket.I
  2. 4 4
      panda/src/builder/builderBucket.h
  3. 7 7
      panda/src/builder/builderFuncs.I
  4. 3 3
      panda/src/builder/builderPrim.cxx
  5. 5 5
      panda/src/builder/builderPrimTempl.I
  6. 5 5
      panda/src/builder/builderPrimTempl.h
  7. 4 4
      panda/src/builder/builderVertex.I
  8. 4 4
      panda/src/builder/builderVertex.h
  9. 5 5
      panda/src/builder/builderVertexTempl.I
  10. 6 6
      panda/src/builder/builderVertexTempl.h
  11. 12 0
      panda/src/display/graphicsStateGuardian.I
  12. 69 0
      panda/src/display/graphicsStateGuardian.cxx
  13. 12 0
      panda/src/display/graphicsStateGuardian.h
  14. 2 2
      panda/src/distort/projectionScreen.I
  15. 1 1
      panda/src/distort/projectionScreen.cxx
  16. 3 3
      panda/src/distort/projectionScreen.h
  17. 77 0
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  18. 4 0
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  19. 5 5
      panda/src/egg2pg/computedVerticesMaker.cxx
  20. 5 5
      panda/src/egg2pg/computedVerticesMaker.h
  21. 18 17
      panda/src/egg2pg/eggLoader.cxx
  22. 2 2
      panda/src/egg2pg/eggLoader.h
  23. 4 0
      panda/src/express/numeric_types.h
  24. 14 12
      panda/src/express/pointerToArray.I
  25. 4 4
      panda/src/express/pointerToArray.h
  26. 125 51
      panda/src/framework/windowFramework.cxx
  27. 3 0
      panda/src/glstuff/Sources.pp
  28. 27 0
      panda/src/glstuff/glGeomMunger_src.I
  29. 52 0
      panda/src/glstuff/glGeomMunger_src.cxx
  30. 54 0
      panda/src/glstuff/glGeomMunger_src.h
  31. 192 0
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  32. 11 0
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  33. 1 0
      panda/src/glstuff/glstuff_src.cxx
  34. 1 0
      panda/src/glstuff/glstuff_src.h
  35. 30 5
      panda/src/gobj/Sources.pp
  36. 34 3
      panda/src/gobj/config_gobj.cxx
  37. 2 0
      panda/src/gobj/config_gobj.h
  38. 9 9
      panda/src/gobj/geom.I
  39. 73 15
      panda/src/gobj/geom.cxx
  40. 15 15
      panda/src/gobj/geom.h
  41. 11 1
      panda/src/gobj/gobj_composite1.cxx
  42. 1 1
      panda/src/gobj/gobj_composite2.cxx
  43. 185 0
      panda/src/gobj/internalName.I
  44. 231 0
      panda/src/gobj/internalName.cxx
  45. 129 0
      panda/src/gobj/internalName.h
  46. 114 0
      panda/src/gobj/qpgeom.I
  47. 395 0
      panda/src/gobj/qpgeom.cxx
  48. 139 0
      panda/src/gobj/qpgeom.h
  49. 113 0
      panda/src/gobj/qpgeomMunger.I
  50. 282 0
      panda/src/gobj/qpgeomMunger.cxx
  51. 121 0
      panda/src/gobj/qpgeomMunger.h
  52. 132 0
      panda/src/gobj/qpgeomPrimitive.I
  53. 520 0
      panda/src/gobj/qpgeomPrimitive.cxx
  54. 156 0
      panda/src/gobj/qpgeomPrimitive.h
  55. 110 0
      panda/src/gobj/qpgeomTriangles.cxx
  56. 68 0
      panda/src/gobj/qpgeomTriangles.h
  57. 138 0
      panda/src/gobj/qpgeomTrifans.cxx
  58. 68 0
      panda/src/gobj/qpgeomTrifans.h
  59. 148 0
      panda/src/gobj/qpgeomTristrips.cxx
  60. 68 0
      panda/src/gobj/qpgeomTristrips.h
  61. 121 0
      panda/src/gobj/qpgeomVertexArrayFormat.I
  62. 556 0
      panda/src/gobj/qpgeomVertexArrayFormat.cxx
  63. 162 0
      panda/src/gobj/qpgeomVertexArrayFormat.h
  64. 82 0
      panda/src/gobj/qpgeomVertexData.I
  65. 650 0
      panda/src/gobj/qpgeomVertexData.cxx
  66. 155 0
      panda/src/gobj/qpgeomVertexData.h
  67. 221 0
      panda/src/gobj/qpgeomVertexDataType.I
  68. 309 0
      panda/src/gobj/qpgeomVertexDataType.cxx
  69. 109 0
      panda/src/gobj/qpgeomVertexDataType.h
  70. 260 0
      panda/src/gobj/qpgeomVertexFormat.I
  71. 632 0
      panda/src/gobj/qpgeomVertexFormat.cxx
  72. 211 0
      panda/src/gobj/qpgeomVertexFormat.h
  73. 380 0
      panda/src/gobj/qpgeomVertexIterator.I
  74. 19 0
      panda/src/gobj/qpgeomVertexIterator.cxx
  75. 86 0
      panda/src/gobj/qpgeomVertexIterator.h
  76. 0 49
      panda/src/gobj/texCoordName.I
  77. 0 161
      panda/src/gobj/texCoordName.cxx
  78. 0 92
      panda/src/gobj/texCoordName.h
  79. 4 4
      panda/src/gobj/textureStage.I
  80. 3 3
      panda/src/gobj/textureStage.cxx
  81. 4 4
      panda/src/gobj/textureStage.h
  82. 5 5
      panda/src/grutil/multitexReducer.cxx
  83. 1 1
      panda/src/grutil/multitexReducer.h
  84. 10 0
      panda/src/gsgbase/graphicsStateGuardianBase.h
  85. 4 4
      panda/src/pgraph/geomNode.I
  86. 2 2
      panda/src/pgraph/geomNode.cxx
  87. 3 3
      panda/src/pgraph/geomNode.h
  88. 4 4
      panda/src/pgraph/geomTransformer.cxx
  89. 5 5
      panda/src/pgraph/geomTransformer.h

+ 2 - 2
panda/src/builder/builderBucket.I

@@ -73,7 +73,7 @@ get_normals() const {
 //               associated with this bucket.
 //               associated with this bucket.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void BuilderBucket::
 INLINE void BuilderBucket::
-set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords) {
+set_texcoords(const InternalName *name, const PTA_TexCoordf &texcoords) {
   _texcoords[name] = texcoords;
   _texcoords[name] = texcoords;
 }
 }
 
 
@@ -84,7 +84,7 @@ set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords) {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PTA_TexCoordf BuilderBucket::
 INLINE PTA_TexCoordf BuilderBucket::
-get_texcoords(const TexCoordName *name) const {
+get_texcoords(const InternalName *name) const {
   TexCoords::const_iterator ti = _texcoords.find(name);
   TexCoords::const_iterator ti = _texcoords.find(name);
   if (ti != _texcoords.end()) {
   if (ti != _texcoords.end()) {
     return (*ti).second;
     return (*ti).second;

+ 4 - 4
panda/src/builder/builderBucket.h

@@ -30,7 +30,7 @@
 #include "pta_Normalf.h"
 #include "pta_Normalf.h"
 #include "pta_Colorf.h"
 #include "pta_Colorf.h"
 #include "pta_TexCoordf.h"
 #include "pta_TexCoordf.h"
-#include "texCoordName.h"
+#include "internalName.h"
 #include "renderState.h"
 #include "renderState.h"
 
 
 #include "stdlib.h"
 #include "stdlib.h"
@@ -77,8 +77,8 @@ public:
   INLINE void set_normals(const PTA_Normalf &normals);
   INLINE void set_normals(const PTA_Normalf &normals);
   INLINE PTA_Normalf get_normals() const;
   INLINE PTA_Normalf get_normals() const;
 
 
-  INLINE void set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords);
-  INLINE PTA_TexCoordf get_texcoords(const TexCoordName *name) const;
+  INLINE void set_texcoords(const InternalName *name, const PTA_TexCoordf &texcoords);
+  INLINE PTA_TexCoordf get_texcoords(const InternalName *name) const;
 
 
   INLINE void set_colors(const PTA_Colorf &colors);
   INLINE void set_colors(const PTA_Colorf &colors);
   INLINE PTA_Colorf get_colors() const;
   INLINE PTA_Colorf get_colors() const;
@@ -96,7 +96,7 @@ protected:
   PTA_Normalf _normals;
   PTA_Normalf _normals;
   PTA_Colorf _colors;
   PTA_Colorf _colors;
 
 
-  typedef pmap<CPT(TexCoordName), PTA_TexCoordf> TexCoords;
+  typedef pmap<CPT(InternalName), PTA_TexCoordf> TexCoords;
   TexCoords _texcoords;
   TexCoords _texcoords;
 
 
   static BuilderBucket *_default_bucket;
   static BuilderBucket *_default_bucket;

+ 7 - 7
panda/src/builder/builderFuncs.I

@@ -555,13 +555,13 @@ build_geoms(InputIterator first, InputIterator last,
   //
   //
   // Texcoords are an exception to the above, since they are either
   // Texcoords are an exception to the above, since they are either
   // per vertex or not at all, and since there may be a different set
   // per vertex or not at all, and since there may be a different set
-  // of texcoords for each of a number of TexCoordName objects.
+  // of texcoords for each of a number of InternalName objects.
 
 
   GeomBindType bind_normals = G_OVERALL;
   GeomBindType bind_normals = G_OVERALL;
   GeomBindType bind_colors = G_OVERALL;
   GeomBindType bind_colors = G_OVERALL;
 
 
-  typedef pset<const TexCoordName *> TexCoordNames;
-  TexCoordNames texcoord_names;
+  typedef pset<const InternalName *> InternalNames;
+  InternalNames texcoord_names;
 
 
   NType overall_normal(0);
   NType overall_normal(0);
   CType overall_color(0);
   CType overall_color(0);
@@ -623,11 +623,11 @@ build_geoms(InputIterator first, InputIterator last,
       }
       }
     }
     }
 
 
-    // Texcoords.  Get the union of all TexCoordNames defined on the
+    // Texcoords.  Get the union of all InternalNames defined on the
     // prims.
     // prims.
     TYPENAME PrimType::tcn_const_iterator tni;
     TYPENAME PrimType::tcn_const_iterator tni;
     for (tni = (*i).tcn_begin(); tni != (*i).tcn_end(); ++tni) {
     for (tni = (*i).tcn_begin(); tni != (*i).tcn_end(); ++tni) {
-      const TexCoordName *name = (*tni);
+      const InternalName *name = (*tni);
       texcoord_names.insert(name);
       texcoord_names.insert(name);
     }
     }
   }
   }
@@ -719,7 +719,7 @@ build_geoms(InputIterator first, InputIterator last,
 
 
   typedef TYPENAME PrimType::TexCoordFill TexCoordFill;
   typedef TYPENAME PrimType::TexCoordFill TexCoordFill;
   TexCoordFill texcoords;
   TexCoordFill texcoords;
-  TexCoordNames::const_iterator tni;
+  InternalNames::const_iterator tni;
   for (tni = texcoord_names.begin(); tni != texcoord_names.end(); ++tni) {
   for (tni = texcoord_names.begin(); tni != texcoord_names.end(); ++tni) {
     texcoords[*tni] = PTA(TType)::empty_array(0);
     texcoords[*tni] = PTA(TType)::empty_array(0);
   }
   }
@@ -744,7 +744,7 @@ build_geoms(InputIterator first, InputIterator last,
         }
         }
         TYPENAME TexCoordFill::iterator tci;
         TYPENAME TexCoordFill::iterator tci;
         for (tci = texcoords.begin(); tci != texcoords.end(); ++tci) {
         for (tci = texcoords.begin(); tci != texcoords.end(); ++tci) {
-          const TexCoordName *name = (*tci).first;
+          const InternalName *name = (*tci).first;
           if ((*i).get_vertex(v).has_texcoord(name)) {
           if ((*i).get_vertex(v).has_texcoord(name)) {
             (*tci).second.push_back((*i).get_vertex(v).get_texcoord(name));
             (*tci).second.push_back((*i).get_vertex(v).get_texcoord(name));
           } else {
           } else {

+ 3 - 3
panda/src/builder/builderPrim.cxx

@@ -68,7 +68,7 @@ nonindexed_copy(const BuilderPrimTempl<BuilderVertexI> &copy,
     
     
     BuilderVertexI::tc_const_iterator tci;
     BuilderVertexI::tc_const_iterator tci;
     for (tci = cv.tc_begin(); tci != cv.tc_end(); ++tci) {
     for (tci = cv.tc_begin(); tci != cv.tc_end(); ++tci) {
-      const TexCoordName *name = (*tci).first;
+      const InternalName *name = (*tci).first;
       v.set_texcoord(name, cv.get_texcoord_value(name, bucket));
       v.set_texcoord(name, cv.get_texcoord_value(name, bucket));
     }
     }
 
 
@@ -153,7 +153,7 @@ fill_geom(Geom *geom, const PTA_BuilderV &v_array,
 
 
   TexCoordFill::const_iterator tci;
   TexCoordFill::const_iterator tci;
   for (tci = texcoords.begin(); tci != texcoords.end(); ++tci) {
   for (tci = texcoords.begin(); tci != texcoords.end(); ++tci) {
-    const TexCoordName *name = (*tci).first;
+    const InternalName *name = (*tci).first;
     geom->set_texcoords(name, (*tci).second);
     geom->set_texcoords(name, (*tci).second);
   }
   }
 }
 }
@@ -238,7 +238,7 @@ fill_geom(Geom *geom, const PTA_ushort &v_array,
 
 
   TexCoordFill::const_iterator tci;
   TexCoordFill::const_iterator tci;
   for (tci = texcoords.begin(); tci != texcoords.end(); ++tci) {
   for (tci = texcoords.begin(); tci != texcoords.end(); ++tci) {
-    const TexCoordName *name = (*tci).first;
+    const InternalName *name = (*tci).first;
     PTA_ushort t_array = (*tci).second;
     PTA_ushort t_array = (*tci).second;
 
 
     PTA_TexCoordf t_data = bucket.get_texcoords(name);
     PTA_TexCoordf t_data = bucket.get_texcoords(name);

+ 5 - 5
panda/src/builder/builderPrimTempl.I

@@ -328,7 +328,7 @@ has_any_pixel_size() const {
 //     Function: BuilderPrimTempl::tcn_begin
 //     Function: BuilderPrimTempl::tcn_begin
 //       Access: Public
 //       Access: Public
 //  Description: Returns an iterator that can be used to walk through
 //  Description: Returns an iterator that can be used to walk through
-//               the list of TexCoordNames that are common to all
+//               the list of InternalNames that are common to all
 //               vertices on this primitive.
 //               vertices on this primitive.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VTX>
 template <class VTX>
@@ -341,7 +341,7 @@ tcn_begin() const {
 //     Function: BuilderPrimTempl::tcn_end
 //     Function: BuilderPrimTempl::tcn_end
 //       Access: Public
 //       Access: Public
 //  Description: Returns an iterator that can be used to walk through
 //  Description: Returns an iterator that can be used to walk through
-//               the list of TexCoordNames that are common to all
+//               the list of InternalNames that are common to all
 //               vertices on this primitive.
 //               vertices on this primitive.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VTX>
 template <class VTX>
@@ -353,7 +353,7 @@ tcn_end() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: BuilderPrimTempl::tcn_size
 //     Function: BuilderPrimTempl::tcn_size
 //       Access: Public
 //       Access: Public
-//  Description: Returns the number of TexCoordNames that are common
+//  Description: Returns the number of InternalNames that are common
 //               to all vertices on this primitive.
 //               to all vertices on this primitive.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VTX>
 template <class VTX>
@@ -885,12 +885,12 @@ update_overall_attrib() {
 
 
   int i;
   int i;
   if (num_verts > 0) {
   if (num_verts > 0) {
-    // Get the intersection of TexCoordNames that are defined on all
+    // Get the intersection of InternalNames that are defined on all
     // vertices.
     // vertices.
     const Vertex &vtx = get_vertex(0);
     const Vertex &vtx = get_vertex(0);
     TYPENAME Vertex::tc_const_iterator tci;
     TYPENAME Vertex::tc_const_iterator tci;
     for (tci = vtx.tc_begin(); tci != vtx.tc_end(); ++tci) {
     for (tci = vtx.tc_begin(); tci != vtx.tc_end(); ++tci) {
-      const TexCoordName *name = (*tci).first;
+      const InternalName *name = (*tci).first;
       bool has_texcoord = true;
       bool has_texcoord = true;
       for (i = 1; i < num_verts && has_texcoord; i++) {
       for (i = 1; i < num_verts && has_texcoord; i++) {
         has_texcoord = get_vertex(i).has_texcoord(name);
         has_texcoord = get_vertex(i).has_texcoord(name);

+ 5 - 5
panda/src/builder/builderPrimTempl.h

@@ -45,12 +45,12 @@ public:
   typedef TYPENAME VTX::TType TType;
   typedef TYPENAME VTX::TType TType;
   typedef TYPENAME VTX::CType CType;
   typedef TYPENAME VTX::CType CType;
   typedef TYPENAME VTX::Attrib DAttrib;
   typedef TYPENAME VTX::Attrib DAttrib;
-  typedef pset<const TexCoordName *> TexCoordNames;
-  typedef TexCoordNames::const_iterator tcn_const_iterator;
-  typedef TexCoordNames::size_type tcn_size_type;
+  typedef pset<const InternalName *> InternalNames;
+  typedef InternalNames::const_iterator tcn_const_iterator;
+  typedef InternalNames::size_type tcn_size_type;
 
 
   // This type is passed to fill_geom() for the texcoords.
   // This type is passed to fill_geom() for the texcoords.
-  typedef pmap<const TexCoordName *, PTA(TType) > TexCoordFill;
+  typedef pmap<const InternalName *, PTA(TType) > TexCoordFill;
 
 
   INLINE BuilderPrimTempl();
   INLINE BuilderPrimTempl();
   INLINE BuilderPrimTempl(const BuilderPrimTempl &copy);
   INLINE BuilderPrimTempl(const BuilderPrimTempl &copy);
@@ -151,7 +151,7 @@ protected:
 
 
   Verts _verts;
   Verts _verts;
   Components _components;
   Components _components;
-  TexCoordNames _texcoord_names;
+  InternalNames _texcoord_names;
   BuilderPrimType _type;
   BuilderPrimType _type;
   int _overall;
   int _overall;
 };
 };

+ 4 - 4
panda/src/builder/builderVertex.I

@@ -60,7 +60,7 @@ set_normal_value(const BuilderN *array, ushort index) {
 //               assumes the array is the same one it's indexing on).
 //               assumes the array is the same one it's indexing on).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void BuilderVertex::
 INLINE void BuilderVertex::
-set_texcoord_value(const TexCoordName *name, const BuilderTC *array, ushort index) {
+set_texcoord_value(const InternalName *name, const BuilderTC *array, ushort index) {
   set_texcoord(name, array[index]);
   set_texcoord(name, array[index]);
 }
 }
 
 
@@ -130,7 +130,7 @@ get_normal_value(const BuilderBucket &) const {
 //               get_coord_value().
 //               get_coord_value().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE BuilderTC BuilderVertex::
 INLINE BuilderTC BuilderVertex::
-get_texcoord_value(const TexCoordName *name, const BuilderBucket &) const {
+get_texcoord_value(const InternalName *name, const BuilderBucket &) const {
   return get_texcoord(name);
   return get_texcoord(name);
 }
 }
 
 
@@ -191,7 +191,7 @@ set_normal_value(const BuilderN *, ushort index) {
 //               assumes the array is the same one it's indexing on).
 //               assumes the array is the same one it's indexing on).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void BuilderVertexI::
 INLINE void BuilderVertexI::
-set_texcoord_value(const TexCoordName *name,const BuilderTC *, ushort index) {
+set_texcoord_value(const InternalName *name,const BuilderTC *, ushort index) {
   set_texcoord(name, index);
   set_texcoord(name, index);
 }
 }
 
 
@@ -259,7 +259,7 @@ get_normal_value(const BuilderBucket &bucket) const {
 //               get_coord_value().
 //               get_coord_value().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE BuilderTC BuilderVertexI::
 INLINE BuilderTC BuilderVertexI::
-get_texcoord_value(const TexCoordName *name, const BuilderBucket &bucket) const {
+get_texcoord_value(const InternalName *name, const BuilderBucket &bucket) const {
   nassertr(bucket.get_texcoords(name) != (TexCoordf *)NULL, BuilderTC());
   nassertr(bucket.get_texcoords(name) != (TexCoordf *)NULL, BuilderTC());
   return bucket.get_texcoords(name)[get_texcoord(name)];
   return bucket.get_texcoords(name)[get_texcoord(name)];
 }
 }

+ 4 - 4
panda/src/builder/builderVertex.h

@@ -80,12 +80,12 @@ public:
 
 
   INLINE void set_coord_value(const BuilderV *array, ushort index);
   INLINE void set_coord_value(const BuilderV *array, ushort index);
   INLINE void set_normal_value(const BuilderN *array, ushort index);
   INLINE void set_normal_value(const BuilderN *array, ushort index);
-  INLINE void set_texcoord_value(const TexCoordName *name, const BuilderTC *array, ushort index);
+  INLINE void set_texcoord_value(const InternalName *name, const BuilderTC *array, ushort index);
   INLINE void set_color_value(const BuilderC *array, ushort index);
   INLINE void set_color_value(const BuilderC *array, ushort index);
 
 
   INLINE BuilderV get_coord_value(const BuilderBucket &bucket) const;
   INLINE BuilderV get_coord_value(const BuilderBucket &bucket) const;
   INLINE BuilderN get_normal_value(const BuilderBucket &bucket) const;
   INLINE BuilderN get_normal_value(const BuilderBucket &bucket) const;
-  INLINE BuilderTC get_texcoord_value(const TexCoordName *name, const BuilderBucket &bucket) const;
+  INLINE BuilderTC get_texcoord_value(const InternalName *name, const BuilderBucket &bucket) const;
   INLINE BuilderC get_color_value(const BuilderBucket &bucket) const;
   INLINE BuilderC get_color_value(const BuilderBucket &bucket) const;
 
 
 };
 };
@@ -111,12 +111,12 @@ public:
 
 
   INLINE void set_coord_value(const BuilderV *array, ushort index);
   INLINE void set_coord_value(const BuilderV *array, ushort index);
   INLINE void set_normal_value(const BuilderN *array, ushort index);
   INLINE void set_normal_value(const BuilderN *array, ushort index);
-  INLINE void set_texcoord_value(const TexCoordName *name, const BuilderTC *array, ushort index);
+  INLINE void set_texcoord_value(const InternalName *name, const BuilderTC *array, ushort index);
   INLINE void set_color_value(const BuilderC *array, ushort index);
   INLINE void set_color_value(const BuilderC *array, ushort index);
 
 
   INLINE BuilderV get_coord_value(const BuilderBucket &bucket) const;
   INLINE BuilderV get_coord_value(const BuilderBucket &bucket) const;
   INLINE BuilderN get_normal_value(const BuilderBucket &bucket) const;
   INLINE BuilderN get_normal_value(const BuilderBucket &bucket) const;
-  INLINE BuilderTC get_texcoord_value(const TexCoordName *name, const BuilderBucket &bucket) const;
+  INLINE BuilderTC get_texcoord_value(const InternalName *name, const BuilderBucket &bucket) const;
   INLINE BuilderC get_color_value(const BuilderBucket &bucket) const;
   INLINE BuilderC get_color_value(const BuilderBucket &bucket) const;
 };
 };
 
 

+ 5 - 5
panda/src/builder/builderVertexTempl.I

@@ -170,7 +170,7 @@ clear_normal() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VT, class NT, class TT, class CT>
 template <class VT, class NT, class TT, class CT>
 INLINE bool BuilderVertexTempl<VT, NT, TT, CT>::
 INLINE bool BuilderVertexTempl<VT, NT, TT, CT>::
-has_texcoord(const TexCoordName *name) const {
+has_texcoord(const InternalName *name) const {
   TYPENAME TexCoords::const_iterator ti = _texcoords.find(name);
   TYPENAME TexCoords::const_iterator ti = _texcoords.find(name);
   return (ti != _texcoords.end());
   return (ti != _texcoords.end());
 }
 }
@@ -185,7 +185,7 @@ has_texcoord(const TexCoordName *name) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VT, class NT, class TT, class CT>
 template <class VT, class NT, class TT, class CT>
 INLINE TYPENAME BuilderVertexTempl<VT, NT, TT, CT>::TType BuilderVertexTempl<VT, NT, TT, CT>::
 INLINE TYPENAME BuilderVertexTempl<VT, NT, TT, CT>::TType BuilderVertexTempl<VT, NT, TT, CT>::
-get_texcoord(const TexCoordName *name) const {
+get_texcoord(const InternalName *name) const {
   TYPENAME TexCoords::const_iterator ti = _texcoords.find(name);
   TYPENAME TexCoords::const_iterator ti = _texcoords.find(name);
   nassertr(ti != _texcoords.end(), (*ti).second);
   nassertr(ti != _texcoords.end(), (*ti).second);
   return (*ti).second;
   return (*ti).second;
@@ -199,7 +199,7 @@ get_texcoord(const TexCoordName *name) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VT, class NT, class TT, class CT>
 template <class VT, class NT, class TT, class CT>
 INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
 INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
-set_texcoord(const TexCoordName *name, const TType &t) {
+set_texcoord(const InternalName *name, const TType &t) {
   _texcoords[name] = t;
   _texcoords[name] = t;
   return *this;
   return *this;
 }
 }
@@ -211,7 +211,7 @@ set_texcoord(const TexCoordName *name, const TType &t) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template <class VT, class NT, class TT, class CT>
 template <class VT, class NT, class TT, class CT>
 INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
 INLINE BuilderVertexTempl<VT, NT, TT, CT> &BuilderVertexTempl<VT, NT, TT, CT>::
-clear_texcoord(const TexCoordName *name) {
+clear_texcoord(const InternalName *name) {
   _texcoords.erase(name);
   _texcoords.erase(name);
   return *this;
   return *this;
 }
 }
@@ -422,7 +422,7 @@ output(ostream &out) const {
 
 
     TYPENAME TexCoords::const_iterator ti;
     TYPENAME TexCoords::const_iterator ti;
     for (ti = _texcoords.begin(); ti != _texcoords.end(); ++ti) {
     for (ti = _texcoords.begin(); ti != _texcoords.end(); ++ti) {
-      const TexCoordName *name = (*ti).first;
+      const InternalName *name = (*ti).first;
       out << " texcoord \"" << name->get_name() << "\" " << (*ti).second;
       out << " texcoord \"" << name->get_name() << "\" " << (*ti).second;
     }
     }
 
 

+ 6 - 6
panda/src/builder/builderVertexTempl.h

@@ -24,7 +24,7 @@
 #include "builderTypes.h"
 #include "builderTypes.h"
 #include "builderAttribTempl.h"
 #include "builderAttribTempl.h"
 #include "builder_compare.h"
 #include "builder_compare.h"
-#include "texCoordName.h"
+#include "internalName.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 
 
 #include "notify.h"
 #include "notify.h"
@@ -45,7 +45,7 @@ public:
   typedef NT NType;
   typedef NT NType;
   typedef TT TType;
   typedef TT TType;
   typedef CT CType;
   typedef CT CType;
-  typedef pmap<CPT(TexCoordName), TType> TexCoords;
+  typedef pmap<CPT(InternalName), TType> TexCoords;
   typedef TYPENAME TexCoords::const_iterator tc_const_iterator;
   typedef TYPENAME TexCoords::const_iterator tc_const_iterator;
   typedef TYPENAME TexCoords::size_type tc_size_type;
   typedef TYPENAME TexCoords::size_type tc_size_type;
 
 
@@ -64,10 +64,10 @@ public:
   INLINE BuilderVertexTempl &set_normal(const NType &c);
   INLINE BuilderVertexTempl &set_normal(const NType &c);
   INLINE BuilderVertexTempl &clear_normal();
   INLINE BuilderVertexTempl &clear_normal();
 
 
-  INLINE bool has_texcoord(const TexCoordName *name) const;
-  INLINE TType get_texcoord(const TexCoordName *name) const;
-  INLINE BuilderVertexTempl &set_texcoord(const TexCoordName *name, const TType &t);
-  INLINE BuilderVertexTempl &clear_texcoord(const TexCoordName *name);
+  INLINE bool has_texcoord(const InternalName *name) const;
+  INLINE TType get_texcoord(const InternalName *name) const;
+  INLINE BuilderVertexTempl &set_texcoord(const InternalName *name, const TType &t);
+  INLINE BuilderVertexTempl &clear_texcoord(const InternalName *name);
   INLINE tc_const_iterator tc_begin() const;
   INLINE tc_const_iterator tc_begin() const;
   INLINE tc_const_iterator tc_end() const;
   INLINE tc_const_iterator tc_end() const;
   INLINE tc_size_type tc_size() const;
   INLINE tc_size_type tc_size() const;

+ 12 - 0
panda/src/display/graphicsStateGuardian.I

@@ -285,6 +285,16 @@ get_scene() const {
   return _scene_setup;
   return _scene_setup;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_geom_munger
+//       Access: Public
+//  Description: Returns the current GeomMunger object.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomMunger *GraphicsStateGuardian::
+get_geom_munger() const {
+  return _geom_munger;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::clear
 //     Function: GraphicsStateGuardian::clear
 //       Access: Public
 //       Access: Public
@@ -373,6 +383,7 @@ modify_state(const RenderState *state) {
     _state_pcollector.add_level(1);
     _state_pcollector.add_level(1);
     _state = _state->issue_delta_modify(state, this);
     _state = _state->issue_delta_modify(state, this);
     finish_modify_state();
     finish_modify_state();
+    setup_geom_munger(NULL);
   }
   }
 }
 }
 
 
@@ -400,6 +411,7 @@ set_state(const RenderState *state) {
     _state_pcollector.add_level(1);
     _state_pcollector.add_level(1);
     _state = _state->issue_delta_set(state, this);
     _state = _state->issue_delta_set(state, this);
     finish_modify_state();
     finish_modify_state();
+    setup_geom_munger(NULL);
   }
   }
 }
 }
 
 

+ 69 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -37,6 +37,8 @@
 #include "throw_event.h"
 #include "throw_event.h"
 #include "clockObject.h"
 #include "clockObject.h"
 #include "pStatTimer.h"
 #include "pStatTimer.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomTrifans.h"
 
 
 #include <algorithm>
 #include <algorithm>
 
 
@@ -592,6 +594,58 @@ finish_decal() {
   // No need to do anything special here.
   // No need to do anything special here.
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::begin_draw_primitives()
+//       Access: Public, Virtual
+//  Description: Called before a sequence of draw_primitive()
+//               functions are called, this should prepare the vertex
+//               data for rendering.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+begin_draw_primitives(const qpGeomVertexData *data) {
+  _vertex_data = get_geom_munger()->munge_data(data);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_triangles
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected triangles.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_triangles(qpGeomTriangles *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_tristrips
+//       Access: Public, Virtual
+//  Description: Draws a series of triangle strips.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_tristrips(qpGeomTristrips *primitive) {
+  primitive->decompose(_vertex_data)->draw(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::draw_trifans
+//       Access: Public, Virtual
+//  Description: Draws a series of triangle fans.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+draw_trifans(qpGeomTrifans *primitive) {
+  primitive->decompose(_vertex_data)->draw(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::end_draw_primitives()
+//       Access: Public, Virtual
+//  Description: Called after a sequence of draw_primitive()
+//               functions are called, this should do whatever cleanup
+//               is appropriate.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+end_draw_primitives() {
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::framebuffer_bind_to_texture
 //     Function: GraphicsStateGuardian::framebuffer_bind_to_texture
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -1270,6 +1324,21 @@ finish_modify_state() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::setup_geom_munger
+//       Access: Protected, Virtual
+//  Description: Called after finish_modify_state has completed, this
+//               method sets up the GeomMunger for rendering with the
+//               current state.
+////////////////////////////////////////////////////////////////////
+void GraphicsStateGuardian::
+setup_geom_munger(PT(qpGeomMunger) munger) {
+  if (munger == (qpGeomMunger *)NULL) {
+    munger = new qpGeomMunger;
+  }
+  _geom_munger = qpGeomMunger::register_munger(munger);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::free_pointers
 //     Function: GraphicsStateGuardian::free_pointers
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

+ 12 - 0
panda/src/display/graphicsStateGuardian.h

@@ -44,6 +44,8 @@
 #include "textureAttrib.h"
 #include "textureAttrib.h"
 #include "transparencyAttrib.h"
 #include "transparencyAttrib.h"
 #include "config_display.h"
 #include "config_display.h"
+#include "qpgeomMunger.h"
+#include "qpgeomVertexData.h"
 
 
 #include "notify.h"
 #include "notify.h"
 #include "pvector.h"
 #include "pvector.h"
@@ -95,6 +97,7 @@ PUBLISHED:
 public:
 public:
   INLINE bool set_scene(SceneSetup *scene_setup);
   INLINE bool set_scene(SceneSetup *scene_setup);
   INLINE SceneSetup *get_scene() const;
   INLINE SceneSetup *get_scene() const;
+  INLINE const qpGeomMunger *get_geom_munger() const;
 
 
   virtual PreparedGraphicsObjects *get_prepared_objects();
   virtual PreparedGraphicsObjects *get_prepared_objects();
 
 
@@ -139,6 +142,12 @@ public:
   virtual CPT(RenderState) begin_decal_base_second();
   virtual CPT(RenderState) begin_decal_base_second();
   virtual void finish_decal();
   virtual void finish_decal();
 
 
+  virtual void begin_draw_primitives(const qpGeomVertexData *vertex_data);
+  virtual void draw_triangles(qpGeomTriangles *primitive);
+  virtual void draw_tristrips(qpGeomTristrips *primitive);
+  virtual void draw_trifans(qpGeomTrifans *primitive);
+  virtual void end_draw_primitives();
+
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
   virtual bool framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex);
   virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
   virtual void framebuffer_release_texture(GraphicsOutput *win, Texture *tex);
 
 
@@ -200,6 +209,7 @@ protected:
   virtual void set_blend_mode();
   virtual void set_blend_mode();
 
 
   virtual void finish_modify_state();
   virtual void finish_modify_state();
+  virtual void setup_geom_munger(PT(qpGeomMunger) munger);
 
 
   virtual void free_pointers();
   virtual void free_pointers();
   virtual void close_gsg();
   virtual void close_gsg();
@@ -232,6 +242,8 @@ protected:
 
 
   CPT(RenderState) _state;
   CPT(RenderState) _state;
   CPT(TransformState) _transform;
   CPT(TransformState) _transform;
+  CPT(qpGeomMunger) _geom_munger;
+  CPT(qpGeomVertexData) _vertex_data;
 
 
   int _buffer_mask;
   int _buffer_mask;
   Colorf _color_clear_value;
   Colorf _color_clear_value;

+ 2 - 2
panda/src/distort/projectionScreen.I

@@ -41,7 +41,7 @@ get_projector() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void ProjectionScreen::
 INLINE void ProjectionScreen::
 set_texcoord_name(const string &texcoord_name) {
 set_texcoord_name(const string &texcoord_name) {
-  _texcoord_name = TexCoordName::make(texcoord_name);
+  _texcoord_name = InternalName::get_texcoord_name(texcoord_name);
   _stale = true;
   _stale = true;
 }
 }
 
 
@@ -52,7 +52,7 @@ set_texcoord_name(const string &texcoord_name) {
 //               will be generated by this particular
 //               will be generated by this particular
 //               ProjectionScreen, as set by set_texcoord_name().
 //               ProjectionScreen, as set by set_texcoord_name().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const string &ProjectionScreen::
+INLINE string ProjectionScreen::
 get_texcoord_name() const {
 get_texcoord_name() const {
   return _texcoord_name->get_name();
   return _texcoord_name->get_name();
 }
 }

+ 1 - 1
panda/src/distort/projectionScreen.cxx

@@ -34,7 +34,7 @@ TypeHandle ProjectionScreen::_type_handle;
 ProjectionScreen::
 ProjectionScreen::
 ProjectionScreen(const string &name) : PandaNode(name)
 ProjectionScreen(const string &name) : PandaNode(name)
 {
 {
-  _texcoord_name = TexCoordName::get_default();
+  _texcoord_name = InternalName::get_texcoord();
 
 
   _invert_uvs = project_invert_uvs;
   _invert_uvs = project_invert_uvs;
   _vignette_on = false;
   _vignette_on = false;

+ 3 - 3
panda/src/distort/projectionScreen.h

@@ -25,7 +25,7 @@
 #include "lensNode.h"
 #include "lensNode.h"
 #include "geomNode.h"
 #include "geomNode.h"
 #include "nodePath.h"
 #include "nodePath.h"
-#include "texCoordName.h"
+#include "internalName.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 
 
 class Geom;
 class Geom;
@@ -82,7 +82,7 @@ PUBLISHED:
   PT(PandaNode) make_flat_mesh(const NodePath &this_np, const NodePath &camera);
   PT(PandaNode) make_flat_mesh(const NodePath &this_np, const NodePath &camera);
 
 
   INLINE void set_texcoord_name(const string &texcoord_name);
   INLINE void set_texcoord_name(const string &texcoord_name);
-  INLINE const string &get_texcoord_name() const;
+  INLINE string get_texcoord_name() const;
 
 
   INLINE void set_invert_uvs(bool invert_uvs);
   INLINE void set_invert_uvs(bool invert_uvs);
   INLINE bool get_invert_uvs() const;
   INLINE bool get_invert_uvs() const;
@@ -124,7 +124,7 @@ private:
 
 
   NodePath _projector;
   NodePath _projector;
   PT(LensNode) _projector_node;
   PT(LensNode) _projector_node;
-  CPT(TexCoordName) _texcoord_name;
+  CPT(InternalName) _texcoord_name;
   bool _invert_uvs;
   bool _invert_uvs;
   bool _vignette_on;
   bool _vignette_on;
   Colorf _vignette_color;
   Colorf _vignette_color;

+ 77 - 0
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -48,6 +48,11 @@
 #include "depthOffsetAttrib.h"
 #include "depthOffsetAttrib.h"
 #include "fog.h"
 #include "fog.h"
 #include "throw_event.h"
 #include "throw_event.h"
+#include "qpgeomVertexFormat.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomTriangles.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomTrifans.h"
 
 
 #ifdef DO_PSTATS
 #ifdef DO_PSTATS
 #include "pStatTimer.h"
 #include "pStatTimer.h"
@@ -2575,6 +2580,78 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) {
   _pCurFvfBufPtr = NULL;
   _pCurFvfBufPtr = NULL;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::begin_draw_primitives
+//       Access: Public, Virtual
+//  Description: Called before a sequence of draw_primitive()
+//               functions are called, this should prepare the vertex
+//               buffer if necessary.
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::
+begin_draw_primitives(const qpGeomVertexData *vertex_data) {
+  DO_PSTATS_STUFF(_draw_primitive_pcollector.start());
+
+  GraphicsStateGuardian::begin_draw_primitives(vertex_data);
+
+  const qpGeomVertexFormat *format = _vertex_data->get_format();
+  
+  if (format == qpGeomVertexFormat::get_v3()) {
+    set_vertex_format(D3DFVF_XYZ);
+  } else if (format == qpGeomVertexFormat::get_v3n3()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_NORMAL);
+  } else if (format == qpGeomVertexFormat::get_v3t2()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
+  } else if (format == qpGeomVertexFormat::get_v3n3t2()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
+  } else if (format == qpGeomVertexFormat::get_v3cp() ||
+             format == qpGeomVertexFormat::get_v3c4()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_DIFFUSE);
+  } else if (format == qpGeomVertexFormat::get_v3n3cp() ||
+             format == qpGeomVertexFormat::get_v3n3c4()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_NORMAL);
+  } else if (format == qpGeomVertexFormat::get_v3cpt2() ||
+             format == qpGeomVertexFormat::get_v3c4t2()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
+  } else if (format == qpGeomVertexFormat::get_v3n3cpt2() ||
+             format == qpGeomVertexFormat::get_v3n3c4t2()) {
+    set_vertex_format(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE | D3DFVF_TEX1 | D3DFVF_TEXCOORDSIZE2(0));
+  } else {
+    nassert_raise("Unexpected vertex format");
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::draw_triangles
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected triangles.
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::
+draw_triangles(qpGeomTriangles *primitive) {
+  HRESULT hr = _pD3DDevice->DrawIndexedPrimitiveUP
+    (D3DPT_TRIANGLELIST, 
+     primitive->get_min_vertex(),
+     primitive->get_max_vertex() - primitive->get_min_vertex() + 1,
+     primitive->get_num_primitives(), 
+     primitive->get_vertices(),
+     D3DFMT_INDEX16,
+     vertex_data->get_array_data(0), 
+     vertex_data->get_format()->get_array_format(0)->get_stride());
+
+  TestDrawPrimFailure(DrawPrim,hr,_pD3DDevice,nPrims,0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DXGraphicsStateGuardian8::end_draw_primitives()
+//       Access: Public, Virtual
+//  Description: Called after a sequence of draw_primitive()
+//               functions are called, this should do whatever cleanup
+//               is appropriate.
+////////////////////////////////////////////////////////////////////
+void DXGraphicsStateGuardian8::
+end_draw_primitives() {
+  DO_PSTATS_STUFF(_draw_primitive_pcollector.stop());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::prepare_texture
 //     Function: DXGraphicsStateGuardian8::prepare_texture
 //       Access: Public, Virtual
 //       Access: Public, Virtual

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

@@ -89,6 +89,10 @@ public:
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
 
+  virtual void begin_draw_primitives(const qpGeomVertexData *vertex_data);
+  virtual void draw_triangles(qpGeomTriangles *primitive);
+  virtual void end_draw_primitives();
+
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual void apply_texture(TextureContext *tc);
   virtual void apply_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);

+ 5 - 5
panda/src/egg2pg/computedVerticesMaker.cxx

@@ -26,7 +26,7 @@
 #include "eggNode.h"
 #include "eggNode.h"
 #include "eggGroup.h"
 #include "eggGroup.h"
 #include "eggVertex.h"
 #include "eggVertex.h"
-#include "texCoordName.h"
+#include "internalName.h"
 
 
 #include <algorithm>
 #include <algorithm>
 
 
@@ -257,7 +257,7 @@ add_normal(const Normald &normal, const EggMorphNormalList &morphs,
 //               array.
 //               array.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 int ComputedVerticesMaker::
 int ComputedVerticesMaker::
-add_texcoord(const TexCoordName *name,
+add_texcoord(const InternalName *name,
              const TexCoordd &texcoord, const EggMorphTexCoordList &morphs,
              const TexCoordd &texcoord, const EggMorphTexCoordList &morphs,
              const LMatrix3d &transform) {
              const LMatrix3d &transform) {
   TexCoordDef &def = _tdefmap[name];
   TexCoordDef &def = _tdefmap[name];
@@ -389,7 +389,7 @@ make_computed_vertices(Character *character, CharacterMaker &char_maker) {
 
 
   // Temporary: the ComputedVertices object currently doesn't support
   // Temporary: the ComputedVertices object currently doesn't support
   // multitexture.
   // multitexture.
-  character->_cv._texcoords = _texcoords[TexCoordName::get_default()];
+  character->_cv._texcoords = _texcoords[InternalName::get_texcoord()];
 
 
   // Finally, add in all the morph definitions.
   // Finally, add in all the morph definitions.
   Morphs::const_iterator mi;
   Morphs::const_iterator mi;
@@ -446,12 +446,12 @@ make_computed_vertices(Character *character, CharacterMaker &char_maker) {
 
 
     TexCoordMorphMap::const_iterator mmi;
     TexCoordMorphMap::const_iterator mmi;
     for (mmi = mlist._tmorphs.begin(); mmi != mlist._tmorphs.end(); ++mmi) {
     for (mmi = mlist._tmorphs.begin(); mmi != mlist._tmorphs.end(); ++mmi) {
-      const TexCoordName *name = (*mmi).first;
+      const InternalName *name = (*mmi).first;
       const TexCoordMorphList &tmorphs = (*mmi).second;
       const TexCoordMorphList &tmorphs = (*mmi).second;
 
 
       // Temporary check: the ComputedVertices object currently
       // Temporary check: the ComputedVertices object currently
       // doesn't support multitexture.
       // doesn't support multitexture.
-      if (name == TexCoordName::get_default()) {
+      if (name == InternalName::get_texcoord()) {
         comp_verts->_texcoord_morphs.push_back(ComputedVerticesMorphTexCoord());
         comp_verts->_texcoord_morphs.push_back(ComputedVerticesMorphTexCoord());
         ComputedVerticesMorphTexCoord &mv = comp_verts->_texcoord_morphs.back();
         ComputedVerticesMorphTexCoord &mv = comp_verts->_texcoord_morphs.back();
         mv._slider_index = slider_index;
         mv._slider_index = slider_index;

+ 5 - 5
panda/src/egg2pg/computedVerticesMaker.h

@@ -40,7 +40,7 @@ class ComputedVertices;
 class CharacterMaker;
 class CharacterMaker;
 class EggNode;
 class EggNode;
 class EggVertex;
 class EggVertex;
-class TexCoordName;
+class InternalName;
 
 
 ///////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////
 //       Class : ComputedVerticesMaker
 //       Class : ComputedVerticesMaker
@@ -74,7 +74,7 @@ public:
                  const LMatrix4d &transform);
                  const LMatrix4d &transform);
   int add_normal(const Normald &normal, const EggMorphNormalList &morphs,
   int add_normal(const Normald &normal, const EggMorphNormalList &morphs,
                  const LMatrix4d &transform);
                  const LMatrix4d &transform);
-  int add_texcoord(const TexCoordName *name,
+  int add_texcoord(const InternalName *name,
                    const TexCoordd &texcoord,
                    const TexCoordd &texcoord,
                    const EggMorphTexCoordList &morphs,
                    const EggMorphTexCoordList &morphs,
                    const LMatrix3d &transform);
                    const LMatrix3d &transform);
@@ -90,7 +90,7 @@ public:
   PTA_Normalf _norms;
   PTA_Normalf _norms;
   PTA_Colorf _colors;
   PTA_Colorf _colors;
 
 
-  typedef pmap<const TexCoordName *, PTA_TexCoordf> TexCoords;
+  typedef pmap<const InternalName *, PTA_TexCoordf> TexCoords;
   TexCoords _texcoords;
   TexCoords _texcoords;
 
 
 protected:
 protected:
@@ -98,7 +98,7 @@ protected:
   typedef pmap<int, LVector3f> NormalMorphList;
   typedef pmap<int, LVector3f> NormalMorphList;
   typedef pmap<int, LVector2f> TexCoordMorphList;
   typedef pmap<int, LVector2f> TexCoordMorphList;
   typedef pmap<int, LVector4f> ColorMorphList;
   typedef pmap<int, LVector4f> ColorMorphList;
-  typedef pmap<const TexCoordName *, TexCoordMorphList> TexCoordMorphMap;
+  typedef pmap<const InternalName *, TexCoordMorphList> TexCoordMorphMap;
   class MorphList {
   class MorphList {
   public:
   public:
     VertexMorphList _vmorphs;
     VertexMorphList _vmorphs;
@@ -120,7 +120,7 @@ protected:
     ComputedVerticesMakerTexCoordMap _tmap;
     ComputedVerticesMakerTexCoordMap _tmap;
   };
   };
 
 
-  typedef pmap<const TexCoordName *, TexCoordDef> TexCoordDefMap;
+  typedef pmap<const InternalName *, TexCoordDef> TexCoordDefMap;
   TexCoordDefMap _tdefmap;
   TexCoordDefMap _tdefmap;
 
 
   ComputedVerticesMakerColorMap _cmap;
   ComputedVerticesMakerColorMap _cmap;

+ 18 - 17
panda/src/egg2pg/eggLoader.cxx

@@ -320,11 +320,11 @@ make_nonindexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
         for (ui = egg_vert->uv_begin(); ui != egg_vert->uv_end(); ++ui) {
         for (ui = egg_vert->uv_begin(); ui != egg_vert->uv_end(); ++ui) {
           EggVertexUV *uv_obj = (*ui);
           EggVertexUV *uv_obj = (*ui);
           TexCoordd uv = uv_obj->get_uv();
           TexCoordd uv = uv_obj->get_uv();
-          CPT(TexCoordName) uv_name;
-          if (uv_obj->has_name()) {
-            uv_name = TexCoordName::make(uv_obj->get_name());
+          CPT(InternalName) uv_name;
+          if (uv_obj->has_name() && uv_obj->get_name() != string("default")) {
+            uv_name = InternalName::get_texcoord_name(uv_obj->get_name());
           } else {
           } else {
-            uv_name = TexCoordName::get_default();
+            uv_name = InternalName::get_texcoord();
           }
           }
 
 
           BakeInUVs::const_iterator buv = bake_in_uvs.find(uv_name);
           BakeInUVs::const_iterator buv = bake_in_uvs.find(uv_name);
@@ -453,11 +453,11 @@ make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
       for (ui = egg_vert->uv_begin(); ui != egg_vert->uv_end(); ++ui) {
       for (ui = egg_vert->uv_begin(); ui != egg_vert->uv_end(); ++ui) {
         EggVertexUV *uv_obj = (*ui);
         EggVertexUV *uv_obj = (*ui);
         TexCoordd uv = uv_obj->get_uv();
         TexCoordd uv = uv_obj->get_uv();
-        CPT(TexCoordName) uv_name;
-        if (uv_obj->has_name()) {
-          uv_name = TexCoordName::make(uv_obj->get_name());
+        CPT(InternalName) uv_name;
+        if (uv_obj->has_name() && uv_obj->get_name() != string("default")) {
+          uv_name = InternalName::get_texcoord_name(uv_obj->get_name());
         } else {
         } else {
-          uv_name = TexCoordName::get_default();
+          uv_name = InternalName::get_texcoord();
         }
         }
 
 
         LMatrix3d mat = LMatrix3d::ident_mat();
         LMatrix3d mat = LMatrix3d::ident_mat();
@@ -498,7 +498,7 @@ make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
   for (tci = comp_verts_maker._texcoords.begin();
   for (tci = comp_verts_maker._texcoords.begin();
        tci != comp_verts_maker._texcoords.end();
        tci != comp_verts_maker._texcoords.end();
        ++tci) {
        ++tci) {
-    const TexCoordName *name = (*tci).first;
+    const InternalName *name = (*tci).first;
     bucket.set_texcoords(name, (*tci).second);
     bucket.set_texcoords(name, (*tci).second);
   }
   }
 
 
@@ -1248,9 +1248,10 @@ make_texture_stage(const EggTexture *egg_tex) {
   }
   }
 
 
 
 
-  if (egg_tex->has_uv_name() && !egg_tex->get_uv_name().empty()) {
-    CPT(TexCoordName) name = 
-      TexCoordName::make(egg_tex->get_uv_name());
+  if (egg_tex->has_uv_name() && !egg_tex->get_uv_name().empty() &&
+      egg_tex->get_uv_name() != string("default")) {
+    CPT(InternalName) name = 
+      InternalName::get_texcoord_name(egg_tex->get_uv_name());
     stage->set_texcoord_name(name);
     stage->set_texcoord_name(name);
   }
   }
 
 
@@ -1461,11 +1462,11 @@ setup_bucket(BuilderBucket &bucket, EggLoader::BakeInUVs &bake_in_uvs,
       // if we can safely bake it into the UV's.  (We need to get the
       // if we can safely bake it into the UV's.  (We need to get the
       // complete list of textures that share this same set of UV's
       // complete list of textures that share this same set of UV's
       // per each unique texture matrix.  Whew!)
       // per each unique texture matrix.  Whew!)
-      CPT(TexCoordName) uv_name;
-      if (egg_tex->has_uv_name()) {
-        uv_name = TexCoordName::make(egg_tex->get_uv_name());
+      CPT(InternalName) uv_name;
+      if (egg_tex->has_uv_name() && egg_tex->get_uv_name() != string("default")) {
+        uv_name = InternalName::get_texcoord_name(egg_tex->get_uv_name());
       } else {
       } else {
-        uv_name = TexCoordName::get_default();
+        uv_name = InternalName::get_texcoord();
       }
       }
 
 
       if (has_tex_gen) {
       if (has_tex_gen) {
@@ -1503,7 +1504,7 @@ setup_bucket(BuilderBucket &bucket, EggLoader::BakeInUVs &bake_in_uvs,
   // texture matrix.
   // texture matrix.
   TexMats::const_iterator tmi;
   TexMats::const_iterator tmi;
   for (tmi = tex_mats.begin(); tmi != tex_mats.end(); ++tmi) {
   for (tmi = tex_mats.begin(); tmi != tex_mats.end(); ++tmi) {
-    const TexCoordName *uv_name = (*tmi).first;
+    const InternalName *uv_name = (*tmi).first;
     const TexMatTransforms &tmt = (*tmi).second;
     const TexMatTransforms &tmt = (*tmi).second;
 
 
     if (tmt.size() == 1 && !needs_tex_mat) {
     if (tmt.size() == 1 && !needs_tex_mat) {

+ 2 - 2
panda/src/egg2pg/eggLoader.h

@@ -91,10 +91,10 @@ private:
   // This structure is used internally in setup_bucket().
   // This structure is used internally in setup_bucket().
   typedef pvector<const TextureDef *> TexMatTextures;
   typedef pvector<const TextureDef *> TexMatTextures;
   typedef pmap<LMatrix3d, TexMatTextures> TexMatTransforms;
   typedef pmap<LMatrix3d, TexMatTextures> TexMatTransforms;
-  typedef pmap<CPT(TexCoordName), TexMatTransforms> TexMats;
+  typedef pmap<CPT(InternalName), TexMatTransforms> TexMats;
 
 
   // This structure is returned by setup_bucket().
   // This structure is returned by setup_bucket().
-  typedef pmap<CPT(TexCoordName), const EggTexture *> BakeInUVs;
+  typedef pmap<CPT(InternalName), const EggTexture *> BakeInUVs;
   
   
   void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
   void make_nurbs_curve(EggNurbsCurve *egg_curve, PandaNode *parent,
                         const LMatrix4d &mat);
                         const LMatrix4d &mat);

+ 4 - 0
panda/src/express/numeric_types.h

@@ -44,6 +44,9 @@ typedef PRUint64 PN_uint64;
 
 
 typedef PRFloat64 PN_float64;
 typedef PRFloat64 PN_float64;
 
 
+// NSPR doesn't define a float32.
+typedef float PN_float32;
+
 #else // HAVE_NSPR
 #else // HAVE_NSPR
 
 
 // Without NSPR, and without any other information, we need some
 // Without NSPR, and without any other information, we need some
@@ -66,6 +69,7 @@ typedef unsigned short PN_uint16;
 typedef unsigned long PN_uint32;
 typedef unsigned long PN_uint32;
 
 
 typedef double PN_float64;
 typedef double PN_float64;
+typedef float PN_float32;
 
 
 #endif  // HAVE_NSPR
 #endif  // HAVE_NSPR
 
 

+ 14 - 12
panda/src/express/pointerToArray.I

@@ -228,8 +228,11 @@ back() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
 INLINE TYPENAME PointerToArray<Element>::iterator PointerToArray<Element>::
 INLINE TYPENAME PointerToArray<Element>::iterator PointerToArray<Element>::
-insert(iterator position, const Element &x) const {
-  nassertr((this->_void_ptr) != NULL, position);
+insert(iterator position, const Element &x) {
+  if ((this->_void_ptr) == NULL) {
+    reassign(new RefCountObj<pvector<Element> >);
+    position = end();
+  }
   nassertr(position >= ((To *)(this->_void_ptr))->begin() &&
   nassertr(position >= ((To *)(this->_void_ptr))->begin() &&
            position <= ((To *)(this->_void_ptr))->end(), position);
            position <= ((To *)(this->_void_ptr))->end(), position);
   return ((To *)(this->_void_ptr))->insert(position, x);
   return ((To *)(this->_void_ptr))->insert(position, x);
@@ -242,8 +245,11 @@ insert(iterator position, const Element &x) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
-insert(iterator position, size_type n, const Element &x) const {
-  nassertv((this->_void_ptr) != NULL);
+insert(iterator position, size_type n, const Element &x) {
+  if ((this->_void_ptr) == NULL) {
+    reassign(new RefCountObj<pvector<Element> >);
+    position = end();
+  }
   nassertv(position >= ((To *)(this->_void_ptr))->begin() &&
   nassertv(position >= ((To *)(this->_void_ptr))->begin() &&
            position <= ((To *)(this->_void_ptr))->end());
            position <= ((To *)(this->_void_ptr))->end());
   ((To *)(this->_void_ptr))->insert(position, n, x);
   ((To *)(this->_void_ptr))->insert(position, n, x);
@@ -256,10 +262,8 @@ insert(iterator position, size_type n, const Element &x) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
-erase(iterator position) const {
-  nassertd((this->_void_ptr) != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
-  }
+erase(iterator position) {
+  nassertv((this->_void_ptr) != NULL);
   nassertv(position >= ((To *)(this->_void_ptr))->begin() &&
   nassertv(position >= ((To *)(this->_void_ptr))->begin() &&
            position <= ((To *)(this->_void_ptr))->end());
            position <= ((To *)(this->_void_ptr))->end());
   ((To *)(this->_void_ptr))->erase(position);
   ((To *)(this->_void_ptr))->erase(position);
@@ -272,10 +276,8 @@ erase(iterator position) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 template<class Element>
 template<class Element>
 INLINE void PointerToArray<Element>::
 INLINE void PointerToArray<Element>::
-erase(iterator first, iterator last) const {
-  nassertd((this->_void_ptr) != NULL) {
-    ((PointerToArray<Element> *)this)->reassign(new RefCountObj<pvector<Element> >);
-  }
+erase(iterator first, iterator last) {
+  nassertv((this->_void_ptr) != NULL);
   nassertv(first >= ((To *)(this->_void_ptr))->begin() && first <= ((To *)(this->_void_ptr))->end());
   nassertv(first >= ((To *)(this->_void_ptr))->begin() && first <= ((To *)(this->_void_ptr))->end());
   nassertv(last >= ((To *)(this->_void_ptr))->begin() && last <= ((To *)(this->_void_ptr))->end());
   nassertv(last >= ((To *)(this->_void_ptr))->begin() && last <= ((To *)(this->_void_ptr))->end());
   ((To *)(this->_void_ptr))->erase(first, last);
   ((To *)(this->_void_ptr))->erase(first, last);

+ 4 - 4
panda/src/express/pointerToArray.h

@@ -135,8 +135,8 @@ public:
   INLINE size_type capacity() const;
   INLINE size_type capacity() const;
   INLINE reference front() const;
   INLINE reference front() const;
   INLINE reference back() const;
   INLINE reference back() const;
-  INLINE iterator insert(iterator position, const Element &x) const;
-  INLINE void insert(iterator position, size_type n, const Element &x) const;
+  INLINE iterator insert(iterator position, const Element &x);
+  INLINE void insert(iterator position, size_type n, const Element &x);
 
 
   // We don't define the insert() method that accepts a pair of
   // We don't define the insert() method that accepts a pair of
   // iterators to copy from.  That's problematic because of the whole
   // iterators to copy from.  That's problematic because of the whole
@@ -145,8 +145,8 @@ public:
   // be exported from the DLL, you should use
   // be exported from the DLL, you should use
   // insert_into_vector(pta.v(), ...).
   // insert_into_vector(pta.v(), ...).
 
 
-  INLINE void erase(iterator position) const;
-  INLINE void erase(iterator first, iterator last) const;
+  INLINE void erase(iterator position);
+  INLINE void erase(iterator first, iterator last);
 
 
 PUBLISHED:
 PUBLISHED:
 #if !defined(WIN32_VC)
 #if !defined(WIN32_VC)

+ 125 - 51
panda/src/framework/windowFramework.cxx

@@ -26,8 +26,15 @@
 #include "loader.h"
 #include "loader.h"
 #include "keyboardButton.h"
 #include "keyboardButton.h"
 #include "geomTri.h"
 #include "geomTri.h"
+#include "qpgeom.h"
+#include "qpgeomTriangles.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomVertexFormat.h"
+#include "qpgeomVertexIterator.h"
 #include "texturePool.h"
 #include "texturePool.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
+#include "colorAttrib.h"
 #include "perspectiveLens.h"
 #include "perspectiveLens.h"
 #include "orthographicLens.h"
 #include "orthographicLens.h"
 #include "auto_bind.h"
 #include "auto_bind.h"
@@ -603,31 +610,6 @@ load_model(const NodePath &parent, Filename filename) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 NodePath WindowFramework::
 NodePath WindowFramework::
 load_default_model(const NodePath &parent) {
 load_default_model(const NodePath &parent) {
-  PTA_Vertexf coords;
-  PTA_TexCoordf uvs;
-  PTA_Normalf norms;
-  PTA_Colorf colors;
-  PTA_ushort cindex;
-  
-  coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
-  coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
-  coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
-  uvs.push_back(TexCoordf(0.0, 0.0));
-  uvs.push_back(TexCoordf(1.0, 0.0));
-  uvs.push_back(TexCoordf(0.0, 1.0));
-  norms.push_back(Normalf::back());
-  colors.push_back(Colorf(0.5, 0.5, 1.0, 1.0));
-  cindex.push_back(0);
-  cindex.push_back(0);
-  cindex.push_back(0);
-  
-  PT(GeomTri) geom = new GeomTri;
-  geom->set_num_prims(1);
-  geom->set_coords(coords);
-  geom->set_texcoords(uvs, G_PER_VERTEX);
-  geom->set_normals(norms, G_PER_PRIM);
-  geom->set_colors(colors, G_PER_VERTEX, cindex);
-
   CPT(RenderState) state = RenderState::make_empty();
   CPT(RenderState) state = RenderState::make_empty();
 
 
   // Get the default texture to apply to the triangle; it's compiled
   // Get the default texture to apply to the triangle; it's compiled
@@ -645,7 +627,70 @@ load_default_model(const NodePath &parent) {
   }
   }
   
   
   GeomNode *geomnode = new GeomNode("tri");
   GeomNode *geomnode = new GeomNode("tri");
-  geomnode->add_geom(geom, state);
+
+  if (use_qpgeom) {
+    // New, experimental Geom code.
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData(qpGeomVertexFormat::get_v3n3cpt2());
+    qpGeomVertexIterator vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexIterator normal(vdata, InternalName::get_normal());
+    qpGeomVertexIterator color(vdata, InternalName::get_color());
+    qpGeomVertexIterator texcoord(vdata, InternalName::get_texcoord());
+
+    vertex.set_data3(Vertexf::rfu(0.0, 0.0, 0.0));
+    vertex.set_data3(Vertexf::rfu(1.0, 0.0, 0.0));
+    vertex.set_data3(Vertexf::rfu(0.0, 0.0, 1.0));
+
+    normal.set_data3(Normalf::back());
+    normal.set_data3(Normalf::back());
+    normal.set_data3(Normalf::back());
+
+    color.set_data4(0.5, 0.5, 1.0, 1.0);
+    color.set_data4(0.5, 0.5, 1.0, 1.0);
+    color.set_data4(0.5, 0.5, 1.0, 1.0);
+
+    texcoord.set_data2(0.0, 0.0);
+    texcoord.set_data2(1.0, 0.0);
+    texcoord.set_data2(0.0, 1.0);
+    
+    PT(qpGeomTriangles) tri = new qpGeomTriangles;
+    tri->add_consecutive_vertices(0, 3);
+    tri->close_primitive();
+    
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(tri);
+    
+    geomnode->add_geom(geom, state);
+
+  } else {
+    // Original, tried-and-true Geom code.
+    PTA_Vertexf coords;
+    PTA_TexCoordf uvs;
+    PTA_Normalf norms;
+    PTA_Colorf colors;
+    PTA_ushort cindex;
+    
+    coords.push_back(Vertexf::rfu(0.0, 0.0, 0.0));
+    coords.push_back(Vertexf::rfu(1.0, 0.0, 0.0));
+    coords.push_back(Vertexf::rfu(0.0, 0.0, 1.0));
+    uvs.push_back(TexCoordf(0.0, 0.0));
+    uvs.push_back(TexCoordf(1.0, 0.0));
+    uvs.push_back(TexCoordf(0.0, 1.0));
+    norms.push_back(Normalf::back());
+    colors.push_back(Colorf(0.5, 0.5, 1.0, 1.0));
+    cindex.push_back(0);
+    cindex.push_back(0);
+    cindex.push_back(0);
+    
+    PT(GeomTri) geom = new GeomTri;
+    geom->set_num_prims(1);
+    geom->set_coords(coords);
+    geom->set_texcoords(uvs, G_PER_VERTEX);
+    geom->set_normals(norms, G_PER_PRIM);
+    geom->set_colors(colors, G_PER_VERTEX, cindex);
+
+    geomnode->add_geom(geom, state);
+  }
 
 
   return parent.attach_new_node(geomnode);
   return parent.attach_new_node(geomnode);
 }
 }
@@ -995,7 +1040,6 @@ load_image_as_model(const Filename &filename) {
   tex->set_magfilter(Texture::FT_linear);
   tex->set_magfilter(Texture::FT_linear);
 
 
   // Ok, now make a polygon to show the texture.
   // Ok, now make a polygon to show the texture.
-  PT(GeomNode) card_geode = new GeomNode("card");
 
 
   // Choose the dimensions of the polygon appropriately.
   // Choose the dimensions of the polygon appropriately.
   float left = -x_size / 2.0;
   float left = -x_size / 2.0;
@@ -1003,34 +1047,64 @@ load_image_as_model(const Filename &filename) {
   float bottom = -y_size / 2.0;
   float bottom = -y_size / 2.0;
   float top = y_size / 2.0;
   float top = y_size / 2.0;
 
 
-  GeomTristrip *geoset = new GeomTristrip;
-  PTA_int lengths=PTA_int::empty_array(0);
-  lengths.push_back(4);
-
-  PTA_Vertexf verts;
-  verts.push_back(Vertexf::rfu(left, 0.02f, top));
-  verts.push_back(Vertexf::rfu(left, 0.02f, bottom));
-  verts.push_back(Vertexf::rfu(right, 0.02f, top));
-  verts.push_back(Vertexf::rfu(right, 0.02f, bottom));
+  PT(GeomNode) card_node = new GeomNode("card");
+  card_node->set_attrib(ColorAttrib::make_flat(Colorf(1.0f, 1.0f, 1.0f, 1.0f)));
+  card_node->set_attrib(TextureAttrib::make(tex));
+  if (has_alpha) {
+    card_node->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
+  }
 
 
-  geoset->set_num_prims(1);
-  geoset->set_lengths(lengths);
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData(qpGeomVertexFormat::get_v3t2());
+    qpGeomVertexIterator vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexIterator texcoord(vdata, InternalName::get_texcoord());
 
 
-  geoset->set_coords(verts);
+    vertex.set_data3(Vertexf::rfu(left, 0.02f, top));
+    vertex.set_data3(Vertexf::rfu(left, 0.02f, bottom));
+    vertex.set_data3(Vertexf::rfu(right, 0.02f, top));
+    vertex.set_data3(Vertexf::rfu(right, 0.02f, bottom));
+    
+    texcoord.set_data2(0.0f, 1.0f);
+    texcoord.set_data2(0.0f, 0.0f);
+    texcoord.set_data2(1.0f, 1.0f);
+    texcoord.set_data2(1.0f, 0.0f);
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips;
+    strip->add_consecutive_vertices(0, 4);
+    strip->close_primitive();
+    
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+    
+    card_node->add_geom(geom);
 
 
-  PTA_TexCoordf uvs;
-  uvs.push_back(TexCoordf(0.0f, 1.0f));
-  uvs.push_back(TexCoordf(0.0f, 0.0f));
-  uvs.push_back(TexCoordf(1.0f, 1.0f));
-  uvs.push_back(TexCoordf(1.0f, 0.0f));
-  
-  geoset->set_texcoords(uvs, G_PER_VERTEX);
+  } else {
+    GeomTristrip *geom = new GeomTristrip;
+    PTA_int lengths=PTA_int::empty_array(0);
+    lengths.push_back(4);
+    
+    PTA_Vertexf verts;
+    verts.push_back(Vertexf::rfu(left, 0.02f, top));
+    verts.push_back(Vertexf::rfu(left, 0.02f, bottom));
+    verts.push_back(Vertexf::rfu(right, 0.02f, top));
+    verts.push_back(Vertexf::rfu(right, 0.02f, bottom));
+    
+    geom->set_num_prims(1);
+    geom->set_lengths(lengths);
+    
+    geom->set_coords(verts);
+    
+    PTA_TexCoordf uvs;
+    uvs.push_back(TexCoordf(0.0f, 1.0f));
+    uvs.push_back(TexCoordf(0.0f, 0.0f));
+    uvs.push_back(TexCoordf(1.0f, 1.0f));
+    uvs.push_back(TexCoordf(1.0f, 0.0f));
+    
+    geom->set_texcoords(uvs, G_PER_VERTEX);
 
 
-  card_geode->add_geom(geoset);
-  card_geode->set_attrib(TextureAttrib::make(tex));
-  if (has_alpha) {
-    card_geode->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
+    card_node->add_geom(geom);
   }
   }
 
 
-  return card_geode.p();
+  return card_node.p();
 }
 }

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

@@ -22,6 +22,9 @@
      glGeomContext_src.cxx \
      glGeomContext_src.cxx \
      glGeomContext_src.I \
      glGeomContext_src.I \
      glGeomContext_src.h \
      glGeomContext_src.h \
+     glGeomMunger_src.cxx \
+     glGeomMunger_src.I \
+     glGeomMunger_src.h \
      glGraphicsStateGuardian_src.cxx \
      glGraphicsStateGuardian_src.cxx \
      glGraphicsStateGuardian_src.I \
      glGraphicsStateGuardian_src.I \
      glGraphicsStateGuardian_src.h \
      glGraphicsStateGuardian_src.h \

+ 27 - 0
panda/src/glstuff/glGeomMunger_src.I

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

+ 52 - 0
panda/src/glstuff/glGeomMunger_src.cxx

@@ -0,0 +1,52 @@
+// Filename: glGeomMunger_src.cxx
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+TypeHandle CLP(GeomMunger)::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GeomMunger)::munge_format_impl
+//       Access: Protected, Virtual
+//  Description: Given a source GeomVertexFormat, converts it if
+//               necessary to the appropriate format for rendering.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) CLP(GeomMunger)::
+munge_format_impl(const qpGeomVertexFormat *orig) {
+  CPT(qpGeomVertexFormat) format = 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) {
+    // 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());
+
+    PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*format);
+    PT(qpGeomVertexArrayFormat) new_array_format = new_format->modify_array(color_array);
+
+    // Replace the existing color format with the new format.
+    new_array_format->add_data_type
+      (InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8,
+       color_type->get_start());
+
+    format = qpGeomVertexFormat::register_format(new_format);
+  }
+
+  return format;
+}

+ 54 - 0
panda/src/glstuff/glGeomMunger_src.h

@@ -0,0 +1,54 @@
+// Filename: glGeomMunger_src.h
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+#include "qpgeomMunger.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : GLGeomMunger
+// Description : This specialization on GeomMunger finesses vertices
+//               for OpenGL rendering.  In particular, it makes sure
+//               colors aren't stored in DirectX's packed_argb format.
+////////////////////////////////////////////////////////////////////
+class EXPCL_GL CLP(GeomMunger) : public qpGeomMunger {
+public:
+  INLINE CLP(GeomMunger)();
+
+protected:
+  virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomMunger::init_type();
+    register_type(_type_handle, CLASSPREFIX_QUOTED "GeomMunger",
+                  qpGeomMunger::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "glGeomMunger_src.I"
+

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

@@ -21,6 +21,10 @@
 #include "renderBuffer.h"
 #include "renderBuffer.h"
 #include "geom.h"
 #include "geom.h"
 #include "geomIssuer.h"
 #include "geomIssuer.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomTriangles.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomTrifans.h"
 #include "graphicsWindow.h"
 #include "graphicsWindow.h"
 #include "lens.h"
 #include "lens.h"
 #include "perspectiveLens.h"
 #include "perspectiveLens.h"
@@ -128,6 +132,14 @@ issue_scaled_color_gl(const Geom *geom, Geom::ColorIterator &citerator,
 // defined by the GL, just so it will always be safe to call the
 // defined by the GL, just so it will always be safe to call the
 // extension functions.
 // extension functions.
 
 
+static void APIENTRY
+null_glDrawRangeElements(GLenum mode, GLuint start, GLuint end, 
+                         GLsizei count, GLenum type, const GLvoid *indices) {
+  // If we don't support glDrawRangeElements(), just use the original
+  // glDrawElements() instead.
+  GLP(DrawElements)(mode, count, type, indices);
+}
+
 static void APIENTRY
 static void APIENTRY
 null_glActiveTexture(GLenum gl_texture_stage) {
 null_glActiveTexture(GLenum gl_texture_stage) {
   // If we don't support multitexture, we'd better not try to request
   // If we don't support multitexture, we'd better not try to request
@@ -346,6 +358,27 @@ reset() {
   get_extra_extensions();
   get_extra_extensions();
   report_extensions();
   report_extensions();
 
 
+  if (is_at_least_version(1, 2)) {
+    _supports_draw_range_elements = true;
+    _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
+      get_extension_func(GLPREFIX_QUOTED, "DrawRangeElements");
+
+  } else if (has_extension("EXT_draw_range_elements")) {
+    _supports_draw_range_elements = true;
+    _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
+      get_extension_func(GLPREFIX_QUOTED, "DrawRangeElementsEXT");
+  }
+  if (_supports_draw_range_elements) {
+    if (_glDrawRangeElements == NULL) {
+      GLCAT.warning()
+        << "glDrawRangeElements advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
+      _supports_draw_range_elements = false;
+    }
+  }
+  if (!_supports_draw_range_elements) {
+    _glDrawRangeElements = null_glDrawRangeElements;
+  }
+
   _supports_3d_texture = 
   _supports_3d_texture = 
     has_extension("GL_EXT_texture3D") || is_at_least_version(1, 2);
     has_extension("GL_EXT_texture3D") || is_at_least_version(1, 2);
 
 
@@ -1975,6 +2008,128 @@ draw_sphere(GeomSphere *geom, GeomContext *gc) {
   DO_PSTATS_STUFF(_draw_primitive_pcollector.stop());
   DO_PSTATS_STUFF(_draw_primitive_pcollector.stop());
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::begin_draw_primitives
+//       Access: Public, Virtual
+//  Description: Called before a sequence of draw_primitive()
+//               functions are called, this should prepare the vertex
+//               buffer if necessary.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+begin_draw_primitives(const qpGeomVertexData *vertex_data) {
+  DO_PSTATS_STUFF(_draw_primitive_pcollector.start());
+
+  GraphicsStateGuardian::begin_draw_primitives(vertex_data);
+
+  CPTA_uchar array_data;
+  int num_components;
+  qpGeomVertexDataType::NumericType numeric_type;
+  int start;
+  int stride;
+
+  if (_vertex_data->get_array_info(InternalName::get_vertex(),
+                                   array_data, num_components, numeric_type, 
+                                   start, stride)) {
+    GLP(VertexPointer)(num_components, get_numeric_type(numeric_type), 
+                       stride, array_data + start);
+    GLP(EnableClientState)(GL_VERTEX_ARRAY);
+  } else {
+    GLP(DisableClientState)(GL_VERTEX_ARRAY);
+  }
+
+  bool has_normals = false;
+  if (wants_normals() && 
+      _vertex_data->get_array_info(InternalName::get_normal(),
+                                   array_data, num_components, numeric_type, 
+                                   start, stride)) {
+    GLP(NormalPointer)(get_numeric_type(numeric_type), stride, 
+                       array_data + start);
+    GLP(EnableClientState)(GL_NORMAL_ARRAY);
+    has_normals = true;
+  } else {
+    GLP(DisableClientState)(GL_NORMAL_ARRAY);
+  }
+
+  bool has_colors = false;
+  if (wants_colors()) {
+    if (_vertex_data->get_array_info(InternalName::get_color(),
+                                     array_data, num_components, numeric_type, 
+                                     start, stride)) {
+      if (numeric_type == qpGeomVertexDataType::NT_packed_argb) {
+        // Temporary hack--this will probably reverse r and b.
+        GLP(ColorPointer)(4, GL_UNSIGNED_BYTE, stride, array_data + start);
+        
+      } else {
+        GLP(ColorPointer)(num_components, get_numeric_type(numeric_type), 
+                          stride, array_data + start);
+      }
+      GLP(EnableClientState)(GL_COLOR_ARRAY);
+      has_colors = true;
+
+    } else {
+      // We wanted colors, but the geom didn't have any; just issue
+      // white.
+      GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
+      GLP(DisableClientState)(GL_COLOR_ARRAY);
+    }
+  } else {
+    GLP(DisableClientState)(GL_COLOR_ARRAY);
+  }
+
+  if (wants_texcoords() && 
+      _vertex_data->get_array_info(InternalName::get_texcoord(),
+                                   array_data, num_components, numeric_type, 
+                                   start, stride)) {
+    GLP(TexCoordPointer)(num_components, get_numeric_type(numeric_type), 
+                         stride, array_data + start);
+    GLP(EnableClientState)(GL_TEXTURE_COORD_ARRAY);
+  } else {
+    GLP(DisableClientState)(GL_TEXTURE_COORD_ARRAY);
+  }
+
+  // If we have per-vertex colors or normals, we need smooth shading.
+  // Otherwise we want flat shading for performance reasons.
+  if (has_colors || has_normals) {
+    GLP(ShadeModel)(GL_SMOOTH);
+  } else {
+    GLP(ShadeModel)(GL_FLAT);
+  }
+
+  issue_scene_graph_color();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::draw_triangles
+//       Access: Public, Virtual
+//  Description: Draws a series of disconnected triangles.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+draw_triangles(qpGeomTriangles *primitive) {
+  setup_antialias_polygon();
+
+  _glDrawRangeElements(GL_TRIANGLES, 
+                       primitive->get_min_vertex(),
+                       primitive->get_max_vertex(),
+                       primitive->get_num_vertices(),
+                       GL_UNSIGNED_SHORT, primitive->get_vertices());
+
+  report_my_gl_errors();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::end_draw_primitives()
+//       Access: Public, Virtual
+//  Description: Called after a sequence of draw_primitive()
+//               functions are called, this should do whatever cleanup
+//               is appropriate.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+end_draw_primitives() {
+  GLP(DisableClientState)(GL_VERTEX_ARRAY);
+
+  DO_PSTATS_STUFF(_draw_primitive_pcollector.stop());
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::prepare_texture
 //     Function: CLP(GraphicsStateGuardian)::prepare_texture
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -3762,6 +3917,30 @@ upload_texture_image(CLP(TextureContext) *gtc,
 }
 }
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::get_numeric_type
+//       Access: Protected, Static
+//  Description: Maps from the Geom's internal numeric type symbols
+//               to GL's.
+////////////////////////////////////////////////////////////////////
+GLenum CLP(GraphicsStateGuardian)::
+get_numeric_type(qpGeomVertexDataType::NumericType numeric_type) {
+  switch (numeric_type) {
+  case qpGeomVertexDataType::NT_uint8:
+    return GL_UNSIGNED_BYTE;
+    
+  case qpGeomVertexDataType::NT_packed_argb:
+    return GL_UNSIGNED_INT;
+    
+  case qpGeomVertexDataType::NT_float:
+    return GL_FLOAT;
+  }
+
+  GLCAT.error()
+    << "Invalid NumericType value (" << (int)numeric_type << ")\n";
+  return GL_UNSIGNED_BYTE;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::get_texture_target
 //     Function: CLP(GraphicsStateGuardian)::get_texture_target
 //       Access: Protected
 //       Access: Protected
@@ -4843,6 +5022,19 @@ finish_modify_state() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CLP(GraphicsStateGuardian)::setup_geom_munger
+//       Access: Protected, Virtual
+//  Description: Called after finish_modify_state has completed, this
+//               method sets up the GeomMunger for rendering with the
+//               current state.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+setup_geom_munger(PT(qpGeomMunger) munger) {
+  munger = new CLP(GeomMunger);
+  GraphicsStateGuardian::setup_geom_munger(munger);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CLP(GraphicsStateGuardian)::free_pointers
 //     Function: CLP(GraphicsStateGuardian)::free_pointers
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual

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

@@ -20,6 +20,7 @@
 
 
 #include "graphicsStateGuardian.h"
 #include "graphicsStateGuardian.h"
 #include "geomprimitives.h"
 #include "geomprimitives.h"
+#include "qpgeomVertexDataType.h"
 #include "texture.h"
 #include "texture.h"
 #include "displayRegion.h"
 #include "displayRegion.h"
 #include "material.h"
 #include "material.h"
@@ -48,6 +49,7 @@ class Light;
 // system GL version matches or exceeds the GL version in which these
 // system GL version matches or exceeds the GL version in which these
 // functions are defined, and the system gl.h sometimes doesn't
 // functions are defined, and the system gl.h sometimes doesn't
 // declare these typedefs.
 // declare these typedefs.
+typedef void (APIENTRYP PFNGLDRAWRANGEELEMENTSPROC) (GLenum mode, GLuint start, GLuint end, GLsizei count, GLenum type, const GLvoid *indices);
 typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels);
 typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
 typedef void (APIENTRYP PFNGLACTIVETEXTUREPROC) (GLenum texture);
@@ -87,6 +89,10 @@ public:
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
 
+  virtual void begin_draw_primitives(const qpGeomVertexData *vertex_data);
+  virtual void draw_triangles(qpGeomTriangles *primitive);
+  virtual void end_draw_primitives();
+
   INLINE bool draw_display_list(GeomContext *gc);
   INLINE bool draw_display_list(GeomContext *gc);
 
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
@@ -174,6 +180,7 @@ protected:
   virtual void set_blend_mode();
   virtual void set_blend_mode();
 
 
   virtual void finish_modify_state();
   virtual void finish_modify_state();
+  virtual void setup_geom_munger(PT(qpGeomMunger) munger);
 
 
   virtual void free_pointers();
   virtual void free_pointers();
 
 
@@ -212,6 +219,7 @@ protected:
                             GLint external_format, GLenum component_type, 
                             GLint external_format, GLenum component_type, 
                             const unsigned char *image);
                             const unsigned char *image);
 
 
+  static GLenum get_numeric_type(qpGeomVertexDataType::NumericType numeric_type);
   GLenum get_texture_target(Texture::TextureType texture_type) const;
   GLenum get_texture_target(Texture::TextureType texture_type) const;
   GLenum get_texture_wrap_mode(Texture::WrapMode wm);
   GLenum get_texture_wrap_mode(Texture::WrapMode wm);
   static GLenum get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps);
   static GLenum get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps);
@@ -296,6 +304,9 @@ protected:
   pset<string> _extensions;
   pset<string> _extensions;
 
 
 public:
 public:
+  bool _supports_draw_range_elements;
+  PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements;
+
   bool _supports_3d_texture;
   bool _supports_3d_texture;
   PFNGLTEXIMAGE3DPROC _glTexImage3D;
   PFNGLTEXIMAGE3DPROC _glTexImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;

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

@@ -24,6 +24,7 @@
 #include "glmisc_src.cxx"
 #include "glmisc_src.cxx"
 #include "glTextureContext_src.cxx"
 #include "glTextureContext_src.cxx"
 #include "glGeomContext_src.cxx"
 #include "glGeomContext_src.cxx"
+#include "glGeomMunger_src.cxx"
 #include "glCgShaderContext_src.cxx"
 #include "glCgShaderContext_src.cxx"
 #include "glGraphicsStateGuardian_src.cxx"
 #include "glGraphicsStateGuardian_src.cxx"
 
 

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

@@ -42,6 +42,7 @@
 #include "glmisc_src.h"
 #include "glmisc_src.h"
 #include "glTextureContext_src.h"
 #include "glTextureContext_src.h"
 #include "glGeomContext_src.h"
 #include "glGeomContext_src.h"
+#include "glGeomMunger_src.h"
 #include "glCgShaderContext_src.h"
 #include "glCgShaderContext_src.h"
 #include "glGraphicsStateGuardian_src.h"
 #include "glGraphicsStateGuardian_src.h"
 
 

+ 30 - 5
panda/src/gobj/Sources.pp

@@ -17,6 +17,18 @@
     geomLine.h geomLinestrip.h geomPoint.h geomPolygon.h  \
     geomLine.h geomLinestrip.h geomPoint.h geomPolygon.h  \
     geomQuad.h geomSphere.h geomSprite.I geomSprite.h geomTri.h  \
     geomQuad.h geomSphere.h geomSprite.I geomSprite.h geomTri.h  \
     geomTrifan.h geomTristrip.h  \
     geomTrifan.h geomTristrip.h  \
+    qpgeom.h qpgeom.I \
+    qpgeomMunger.h qpgeomMunger.I \
+    qpgeomPrimitive.h qpgeomPrimitive.I \
+    qpgeomTriangles.h \
+    qpgeomTristrips.h \
+    qpgeomTrifans.h \
+    qpgeomVertexArrayFormat.h qpgeomVertexArrayFormat.I \
+    qpgeomVertexData.h qpgeomVertexData.I \
+    qpgeomVertexDataType.h qpgeomVertexDataType.I \
+    qpgeomVertexFormat.h qpgeomVertexFormat.I \
+    qpgeomVertexIterator.h qpgeomVertexIterator.I \
+    internalName.I internalName.h \
     material.I material.h materialPool.I materialPool.h  \
     material.I material.h materialPool.I materialPool.h  \
     matrixLens.I matrixLens.h \
     matrixLens.I matrixLens.h \
     orthographicLens.I orthographicLens.h perspectiveLens.I  \
     orthographicLens.I orthographicLens.h perspectiveLens.I  \
@@ -27,7 +39,6 @@
     texture.I texture.h \
     texture.I texture.h \
     textureContext.I textureContext.h \
     textureContext.I textureContext.h \
     texturePool.I texturePool.h \
     texturePool.I texturePool.h \
-    texCoordName.I texCoordName.h \
     textureStage.I textureStage.h
     textureStage.I textureStage.h
     
     
   #define INCLUDED_SOURCES \
   #define INCLUDED_SOURCES \
@@ -36,13 +47,26 @@
     geomContext.cxx \
     geomContext.cxx \
     geomLine.cxx geomLinestrip.cxx geomPoint.cxx geomPolygon.cxx  \
     geomLine.cxx geomLinestrip.cxx geomPoint.cxx geomPolygon.cxx  \
     geomQuad.cxx geomSphere.cxx geomSprite.cxx geomTri.cxx  \
     geomQuad.cxx geomSphere.cxx geomSprite.cxx geomTri.cxx  \
-    geomTrifan.cxx geomTristrip.cxx material.cxx  \
+    geomTrifan.cxx geomTristrip.cxx \
+    qpgeom.cxx \
+    qpgeomMunger.cxx \
+    qpgeomPrimitive.cxx \
+    qpgeomTriangles.cxx \
+    qpgeomTristrips.cxx \
+    qpgeomTrifans.cxx \
+    qpgeomVertexArrayFormat.cxx \
+    qpgeomVertexData.cxx \
+    qpgeomVertexDataType.cxx \
+    qpgeomVertexFormat.cxx \
+    qpgeomVertexIterator.cxx \
+    material.cxx  \
+    internalName.cxx \
     materialPool.cxx matrixLens.cxx orthographicLens.cxx  \
     materialPool.cxx matrixLens.cxx orthographicLens.cxx  \
     perspectiveLens.cxx \
     perspectiveLens.cxx \
     preparedGraphicsObjects.cxx \
     preparedGraphicsObjects.cxx \
     lens.cxx  \
     lens.cxx  \
     savedContext.cxx texture.cxx textureContext.cxx texturePool.cxx \
     savedContext.cxx texture.cxx textureContext.cxx texturePool.cxx \
-    texCoordName.cxx textureStage.cxx
+    textureStage.cxx
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
     boundedObject.I boundedObject.h \
     boundedObject.I boundedObject.h \
@@ -52,7 +76,9 @@
     geomLine.h \
     geomLine.h \
     geomLinestrip.h geomPoint.h geomPolygon.h geomQuad.h geomSphere.h \
     geomLinestrip.h geomPoint.h geomPolygon.h geomQuad.h geomSphere.h \
     geomSprite.I geomSprite.h geomTri.h geomTrifan.h geomTristrip.h \
     geomSprite.I geomSprite.h geomTri.h geomTrifan.h geomTristrip.h \
-    geomprimitives.h material.I material.h \
+    geomprimitives.h \
+    internalName.I internalName.h \
+    material.I material.h \
     materialPool.I materialPool.h matrixLens.I matrixLens.h \
     materialPool.I materialPool.h matrixLens.I matrixLens.h \
     orthographicLens.I orthographicLens.h perspectiveLens.I \
     orthographicLens.I orthographicLens.h perspectiveLens.I \
     perspectiveLens.h \
     perspectiveLens.h \
@@ -62,7 +88,6 @@
     texture.I texture.h \
     texture.I texture.h \
     textureContext.I textureContext.h \
     textureContext.I textureContext.h \
     texturePool.I texturePool.h \
     texturePool.I texturePool.h \
-    texCoordName.I texCoordName.h \
     textureStage.I textureStage.h
     textureStage.I textureStage.h
 
 
   #define IGATESCAN all
   #define IGATESCAN all

+ 34 - 3
panda/src/gobj/config_gobj.cxx

@@ -22,6 +22,15 @@
 #include "drawable.h"
 #include "drawable.h"
 #include "geom.h"
 #include "geom.h"
 #include "geomprimitives.h"
 #include "geomprimitives.h"
+#include "qpgeom.h"
+#include "qpgeomMunger.h"
+#include "qpgeomPrimitive.h"
+#include "qpgeomTriangles.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomTrifans.h"
+#include "qpgeomVertexArrayFormat.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomVertexFormat.h"
 #include "material.h"
 #include "material.h"
 #include "orthographicLens.h"
 #include "orthographicLens.h"
 #include "matrixLens.h"
 #include "matrixLens.h"
@@ -29,7 +38,7 @@
 #include "lens.h"
 #include "lens.h"
 #include "texture.h"
 #include "texture.h"
 #include "textureStage.h"
 #include "textureStage.h"
-#include "texCoordName.h"
+#include "internalName.h"
 
 
 #include "dconfig.h"
 #include "dconfig.h"
 #include "string_utils.h"
 #include "string_utils.h"
@@ -72,6 +81,12 @@ ConfigVariableBool retained_mode
           "GSG.  Set it false to use only immediate mode, which sends the "
           "GSG.  Set it false to use only immediate mode, which sends the "
           "vertices to the GSG every frame."));
           "vertices to the GSG every frame."));
 
 
+ConfigVariableBool use_qpgeom
+("use-qpgeom", false,
+ PRC_DESC("A temporary variable while the experimental Geom rewrite is "
+          "underway.  Set this true if you want to use the experimental "
+          "code.  You don't really want to set this true."));
+
 
 
 ConfigVariableEnum<BamTextureMode> bam_texture_mode
 ConfigVariableEnum<BamTextureMode> bam_texture_mode
 ("bam-texture-mode", BTM_relative,
 ("bam-texture-mode", BTM_relative,
@@ -133,6 +148,15 @@ ConfigureFn(config_gobj) {
   GeomTri::init_type();
   GeomTri::init_type();
   GeomTrifan::init_type();
   GeomTrifan::init_type();
   GeomTristrip::init_type();
   GeomTristrip::init_type();
+  qpGeom::init_type();
+  qpGeomMunger::init_type();
+  qpGeomPrimitive::init_type();
+  qpGeomTriangles::init_type();
+  qpGeomTristrips::init_type();
+  qpGeomTrifans::init_type();
+  qpGeomVertexArrayFormat::init_type();
+  qpGeomVertexData::init_type();
+  qpGeomVertexFormat::init_type();
   Material::init_type();
   Material::init_type();
   OrthographicLens::init_type();
   OrthographicLens::init_type();
   MatrixLens::init_type();
   MatrixLens::init_type();
@@ -141,7 +165,7 @@ ConfigureFn(config_gobj) {
   Texture::init_type();
   Texture::init_type();
   dDrawable::init_type();
   dDrawable::init_type();
   TextureStage::init_type();
   TextureStage::init_type();
-  TexCoordName::init_type();
+  InternalName::init_type();
 
 
   //Registration of writeable object's creation
   //Registration of writeable object's creation
   //functions with BamReader's factory
   //functions with BamReader's factory
@@ -155,13 +179,20 @@ ConfigureFn(config_gobj) {
   GeomTristrip::register_with_read_factory();
   GeomTristrip::register_with_read_factory();
   GeomTrifan::register_with_read_factory();
   GeomTrifan::register_with_read_factory();
   GeomSphere::register_with_read_factory();
   GeomSphere::register_with_read_factory();
+  qpGeom::register_with_read_factory();
+  qpGeomTriangles::register_with_read_factory();
+  qpGeomTristrips::register_with_read_factory();
+  qpGeomTrifans::register_with_read_factory();
+  qpGeomVertexArrayFormat::register_with_read_factory();
+  qpGeomVertexData::register_with_read_factory();
+  qpGeomVertexFormat::register_with_read_factory();
   Material::register_with_read_factory();
   Material::register_with_read_factory();
   OrthographicLens::register_with_read_factory();
   OrthographicLens::register_with_read_factory();
   MatrixLens::register_with_read_factory();
   MatrixLens::register_with_read_factory();
   PerspectiveLens::register_with_read_factory();
   PerspectiveLens::register_with_read_factory();
   Texture::register_with_read_factory();
   Texture::register_with_read_factory();
   TextureStage::register_with_read_factory();
   TextureStage::register_with_read_factory();
-  TexCoordName::register_with_read_factory();
+  InternalName::register_with_read_factory();
 }
 }
 
 
 ostream &
 ostream &

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

@@ -52,6 +52,8 @@ extern EXPCL_PANDA ConfigVariableBool keep_texture_ram;
 extern EXPCL_PANDA ConfigVariableBool keep_geom_ram;
 extern EXPCL_PANDA ConfigVariableBool keep_geom_ram;
 extern EXPCL_PANDA ConfigVariableBool retained_mode;
 extern EXPCL_PANDA ConfigVariableBool retained_mode;
 
 
+extern EXPCL_PANDA ConfigVariableBool use_qpgeom;
+
 extern EXPCL_PANDA ConfigVariableEnum<BamTextureMode> bam_texture_mode;
 extern EXPCL_PANDA ConfigVariableEnum<BamTextureMode> bam_texture_mode;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_square;

+ 9 - 9
panda/src/gobj/geom.I

@@ -48,7 +48,7 @@ has_any_texcoords() const {
 //               name, or false otherwise.
 //               name, or false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE bool Geom::
 INLINE bool Geom::
-has_texcoords(const TexCoordName *name) const {
+has_texcoords(const InternalName *name) const {
   TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
   TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
   return (tci != _texcoords_by_name.end());
   return (tci != _texcoords_by_name.end());
 }
 }
@@ -106,11 +106,11 @@ get_colors_array() const {
 //               returns the default texture coordinates only.  In the
 //               returns the default texture coordinates only.  In the
 //               presence of multitexturing, use the version of
 //               presence of multitexturing, use the version of
 //               get_texcoords_array() method that takes a
 //               get_texcoords_array() method that takes a
-//               TexCoordName parameter.
+//               InternalName parameter.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PTA_TexCoordf Geom::
 INLINE PTA_TexCoordf Geom::
 get_texcoords_array() const {
 get_texcoords_array() const {
-  return get_texcoords_array(TexCoordName::get_default());
+  return get_texcoords_array(InternalName::get_texcoord());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -123,7 +123,7 @@ get_texcoords_array() const {
 //               texture coordinates with the indicated name.
 //               texture coordinates with the indicated name.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PTA_TexCoordf Geom::
 INLINE PTA_TexCoordf Geom::
-get_texcoords_array(const TexCoordName *name) const {
+get_texcoords_array(const InternalName *name) const {
   TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
   TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
   if (tci != _texcoords_by_name.end()) {
   if (tci != _texcoords_by_name.end()) {
     return (*tci).second._texcoords;
     return (*tci).second._texcoords;
@@ -174,11 +174,11 @@ get_colors_index() const {
 //               returns the default texture coordinates only.  In the
 //               returns the default texture coordinates only.  In the
 //               presence of multitexturing, use the version of
 //               presence of multitexturing, use the version of
 //               get_texcoords_array() method that takes a
 //               get_texcoords_array() method that takes a
-//               TexCoordName parameter.
+//               InternalName parameter.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PTA_ushort Geom::
 INLINE PTA_ushort Geom::
 get_texcoords_index() const {
 get_texcoords_index() const {
-  return get_texcoords_index(TexCoordName::get_default());
+  return get_texcoords_index(InternalName::get_texcoord());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -192,7 +192,7 @@ get_texcoords_index() const {
 //               the geom does not use indexed texcoords.
 //               the geom does not use indexed texcoords.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PTA_ushort Geom::
 INLINE PTA_ushort Geom::
-get_texcoords_index(const TexCoordName *name) const {
+get_texcoords_index(const InternalName *name) const {
   TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
   TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
   if (tci != _texcoords_by_name.end()) {
   if (tci != _texcoords_by_name.end()) {
     return (*tci).second._tindex;
     return (*tci).second._tindex;
@@ -368,7 +368,7 @@ get_next_normal(NormalIterator &niterator) const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Geom::TexCoordIterator Geom::
 INLINE Geom::TexCoordIterator Geom::
 make_texcoord_iterator() const {
 make_texcoord_iterator() const {
-  return make_texcoord_iterator(TexCoordName::get_default());
+  return make_texcoord_iterator(InternalName::get_texcoord());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -377,7 +377,7 @@ make_texcoord_iterator() const {
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE Geom::TexCoordIterator Geom::
 INLINE Geom::TexCoordIterator Geom::
-make_texcoord_iterator(const TexCoordName *texcoord_name) const {
+make_texcoord_iterator(const InternalName *texcoord_name) const {
   check_config();
   check_config();
   TexCoordIterator i;
   TexCoordIterator i;
 
 

+ 73 - 15
panda/src/gobj/geom.cxx

@@ -392,7 +392,7 @@ set_colors(const PTA_Colorf &colors, GeomBindType bind,
 //       Access: Published
 //       Access: Published
 //  Description: This single-texturing version of set_texcoords() only
 //  Description: This single-texturing version of set_texcoords() only
 //               changes the default texcoords name.  Use the version
 //               changes the default texcoords name.  Use the version
-//               of set_texcoords() that takes a TexCoordName
+//               of set_texcoords() that takes a InternalName
 //               parameter to set up different texture coordinates for
 //               parameter to set up different texture coordinates for
 //               different stages of a multitexture pipeline.
 //               different stages of a multitexture pipeline.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -402,9 +402,9 @@ set_texcoords(const PTA_TexCoordf &texcoords, GeomBindType bind,
   nassertv(bind == G_PER_VERTEX || bind == G_OFF);
   nassertv(bind == G_PER_VERTEX || bind == G_OFF);
 
 
   if (bind == G_OFF) {
   if (bind == G_OFF) {
-    remove_texcoords(TexCoordName::get_default());
+    remove_texcoords(InternalName::get_texcoord());
   } else {
   } else {
-    set_texcoords(TexCoordName::get_default(), texcoords, tindex);
+    set_texcoords(InternalName::get_texcoord(), texcoords, tindex);
   }
   }
 }
 }
 
 
@@ -417,9 +417,9 @@ set_texcoords(const PTA_TexCoordf &texcoords, GeomBindType bind,
 //               remove_texcoords().
 //               remove_texcoords().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Geom::
 void Geom::
-set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords,
+set_texcoords(const InternalName *name, const PTA_TexCoordf &texcoords,
               const PTA_ushort &tindex) {
               const PTA_ushort &tindex) {
-  nassertv(name != (TexCoordName *)NULL);
+  nassertv(name != (InternalName *)NULL);
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG
   // All of the texture coordinates must be either nonindexed, or all
   // All of the texture coordinates must be either nonindexed, or all
@@ -438,7 +438,7 @@ set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords,
   def._texcoords = texcoords;
   def._texcoords = texcoords;
   def._tindex = tindex;
   def._tindex = tindex;
 
 
-  if (name == TexCoordName::get_default()) {
+  if (name == InternalName::get_texcoord()) {
     _bind[G_TEXCOORD] = G_PER_VERTEX;
     _bind[G_TEXCOORD] = G_PER_VERTEX;
   }
   }
 
 
@@ -454,10 +454,10 @@ set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords,
 //               set_texcoords().
 //               set_texcoords().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void Geom::
 void Geom::
-remove_texcoords(const TexCoordName *name) {
+remove_texcoords(const InternalName *name) {
   _texcoords_by_name.erase(name);
   _texcoords_by_name.erase(name);
 
 
-  if (name == TexCoordName::get_default()) {
+  if (name == InternalName::get_texcoord()) {
     _bind[G_TEXCOORD] = G_OFF;
     _bind[G_TEXCOORD] = G_OFF;
   }
   }
 
 
@@ -529,7 +529,7 @@ void Geom::
 get_texcoords(PTA_TexCoordf &texcoords, GeomBindType &bind,
 get_texcoords(PTA_TexCoordf &texcoords, GeomBindType &bind,
               PTA_ushort &tindex) const { 
               PTA_ushort &tindex) const { 
   TexCoordsByName::const_iterator tci = 
   TexCoordsByName::const_iterator tci = 
-    _texcoords_by_name.find(TexCoordName::get_default());
+    _texcoords_by_name.find(InternalName::get_texcoord());
   if (tci != _texcoords_by_name.end()) {
   if (tci != _texcoords_by_name.end()) {
     const TexCoordDef &def = (*tci).second;
     const TexCoordDef &def = (*tci).second;
     texcoords = def._texcoords;
     texcoords = def._texcoords;
@@ -573,6 +573,46 @@ prepare(PreparedGraphicsObjects *prepared_objects) {
   prepared_objects->enqueue_geom(this);
   prepared_objects->enqueue_geom(this);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::get_num_vertices_per_prim
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int Geom::
+get_num_vertices_per_prim() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::get_num_more_vertices_than_components
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int Geom::
+get_num_more_vertices_than_components() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::uses_components
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+bool Geom::
+uses_components() const {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::get_length
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int Geom::
+get_length(int) const {
+  return 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::explode
 //     Function: Geom::explode
 //       Access: Published, Virtual
 //       Access: Published, Virtual
@@ -721,7 +761,7 @@ write_verbose(ostream &out, int indent_level) const {
     for (tci = _texcoords_by_name.begin(); 
     for (tci = _texcoords_by_name.begin(); 
          tci != _texcoords_by_name.end();
          tci != _texcoords_by_name.end();
          ++tci) {
          ++tci) {
-      const TexCoordName *name = (*tci).first;
+      const InternalName *name = (*tci).first;
       const TexCoordDef &def = (*tci).second;
       const TexCoordDef &def = (*tci).second;
       if (def._tindex != (ushort *)NULL) {
       if (def._tindex != (ushort *)NULL) {
         indent(out, indent_level)
         indent(out, indent_level)
@@ -762,7 +802,7 @@ setup_multitexcoord_iterator(MultiTexCoordIterator &iterator,
     if (no_texcoords.find(stage) == no_texcoords.end()) {
     if (no_texcoords.find(stage) == no_texcoords.end()) {
       // This stage is not one of the stages that doesn't need
       // This stage is not one of the stages that doesn't need
       // texcoords issued for it.
       // texcoords issued for it.
-      const TexCoordName *name = stage->get_texcoord_name();
+      const InternalName *name = stage->get_texcoord_name();
       TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
       TexCoordsByName::const_iterator tci = _texcoords_by_name.find(name);
       if (tci != _texcoords_by_name.end()) {
       if (tci != _texcoords_by_name.end()) {
         // This Geom does have texcoords for this stage.
         // This Geom does have texcoords for this stage.
@@ -952,6 +992,24 @@ config() {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::draw_immediate
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void Geom::
+draw_immediate(GraphicsStateGuardianBase *, GeomContext *) {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::print_draw_immediate
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void Geom::
+print_draw_immediate() const {
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::calc_tight_bounds
 //     Function: Geom::calc_tight_bounds
 //       Access: Public
 //       Access: Public
@@ -1118,7 +1176,7 @@ write_datagram(BamWriter *manager, Datagram &me) {
   // write the TexCoordsByName pointers if any
   // write the TexCoordsByName pointers if any
   TexCoordsByName::const_iterator tci;
   TexCoordsByName::const_iterator tci;
   for (tci = _texcoords_by_name.begin(); tci != _texcoords_by_name.end(); ++tci) {
   for (tci = _texcoords_by_name.begin(); tci != _texcoords_by_name.end(); ++tci) {
-    CPT(TexCoordName) tc = (*tci).first;
+    CPT(InternalName) tc = (*tci).first;
     manager->write_pointer(me, tc);
     manager->write_pointer(me, tc);
     WRITE_PTA(manager, me, IPD_TexCoordf::write_datagram, (*tci).second._texcoords);
     WRITE_PTA(manager, me, IPD_TexCoordf::write_datagram, (*tci).second._texcoords);
     WRITE_PTA(manager, me, IPD_ushort::write_datagram, (*tci).second._tindex);
     WRITE_PTA(manager, me, IPD_ushort::write_datagram, (*tci).second._tindex);
@@ -1160,16 +1218,16 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
   for (ci = _temp_texcoord_set.begin();
   for (ci = _temp_texcoord_set.begin();
        ci != _temp_texcoord_set.end();
        ci != _temp_texcoord_set.end();
        ++ci) {
        ++ci) {
-    CPT(TexCoordName) tc = DCAST(TexCoordName, p_list[pi++]);
+    CPT(InternalName) tc = DCAST(InternalName, p_list[pi++]);
     TexCoordDef *def = (*ci);
     TexCoordDef *def = (*ci);
     _texcoords_by_name[tc] = *def;
     _texcoords_by_name[tc] = *def;
     /*
     /*
-    cerr << "TexCoordName from Geom " << (void *)this
+    cerr << "InternalName from Geom " << (void *)this
          << " complete pointers " << tc << " " << *tc 
          << " complete pointers " << tc << " " << *tc 
          << " = " << def->_texcoords << " and " << def->_tindex << "\n";
          << " = " << def->_texcoords << " and " << def->_tindex << "\n";
     */
     */
     delete def;
     delete def;
-    if (tc == TexCoordName::get_default()) {
+    if (tc == InternalName::get_texcoord()) {
       _bind[G_TEXCOORD] = G_PER_VERTEX;
       _bind[G_TEXCOORD] = G_PER_VERTEX;
     }
     }
   }
   }

+ 15 - 15
panda/src/gobj/geom.h

@@ -34,7 +34,7 @@
 #include "pta_TexCoordf.h"
 #include "pta_TexCoordf.h"
 #include "pta_ushort.h"
 #include "pta_ushort.h"
 #include "pta_int.h"
 #include "pta_int.h"
-#include "texCoordName.h"
+#include "internalName.h"
 #include "textureStage.h"
 #include "textureStage.h"
 #include "pset.h"
 #include "pset.h"
 
 
@@ -146,9 +146,9 @@ PUBLISHED:
                   const PTA_ushort &cindex = PTA_ushort());
                   const PTA_ushort &cindex = PTA_ushort());
   void set_texcoords(const PTA_TexCoordf &texcoords, GeomBindType bind,
   void set_texcoords(const PTA_TexCoordf &texcoords, GeomBindType bind,
                      const PTA_ushort &tindex = PTA_ushort());
                      const PTA_ushort &tindex = PTA_ushort());
-  void set_texcoords(const TexCoordName *name, const PTA_TexCoordf &texcoords,
+  void set_texcoords(const InternalName *name, const PTA_TexCoordf &texcoords,
                      const PTA_ushort &tindex = PTA_ushort());
                      const PTA_ushort &tindex = PTA_ushort());
-  void remove_texcoords(const TexCoordName *name);
+  void remove_texcoords(const InternalName *name);
 
 
 public:
 public:
   // These can't be published because of the pass-by-reference
   // These can't be published because of the pass-by-reference
@@ -171,19 +171,19 @@ PUBLISHED:
 
 
   INLINE GeomBindType get_binding(int attr) const;
   INLINE GeomBindType get_binding(int attr) const;
   INLINE bool has_any_texcoords() const;
   INLINE bool has_any_texcoords() const;
-  INLINE bool has_texcoords(const TexCoordName *name) const;
+  INLINE bool has_texcoords(const InternalName *name) const;
 
 
   INLINE PTA_Vertexf get_coords_array() const;
   INLINE PTA_Vertexf get_coords_array() const;
   INLINE PTA_Normalf get_normals_array() const;
   INLINE PTA_Normalf get_normals_array() const;
   INLINE PTA_Colorf get_colors_array() const;
   INLINE PTA_Colorf get_colors_array() const;
   INLINE PTA_TexCoordf get_texcoords_array() const;
   INLINE PTA_TexCoordf get_texcoords_array() const;
-  INLINE PTA_TexCoordf get_texcoords_array(const TexCoordName *name) const;
+  INLINE PTA_TexCoordf get_texcoords_array(const InternalName *name) const;
 
 
   INLINE PTA_ushort get_coords_index() const;
   INLINE PTA_ushort get_coords_index() const;
   INLINE PTA_ushort get_normals_index() const;
   INLINE PTA_ushort get_normals_index() const;
   INLINE PTA_ushort get_colors_index() const;
   INLINE PTA_ushort get_colors_index() const;
   INLINE PTA_ushort get_texcoords_index() const;
   INLINE PTA_ushort get_texcoords_index() const;
-  INLINE PTA_ushort get_texcoords_index(const TexCoordName *name) const;
+  INLINE PTA_ushort get_texcoords_index(const InternalName *name) const;
   INLINE bool are_texcoords_indexed() const;
   INLINE bool are_texcoords_indexed() const;
 
 
   void prepare(PreparedGraphicsObjects *prepared_objects);
   void prepare(PreparedGraphicsObjects *prepared_objects);
@@ -194,16 +194,16 @@ PUBLISHED:
   INLINE void set_lengths(const PTA_int &lengths);
   INLINE void set_lengths(const PTA_int &lengths);
   INLINE PTA_int get_lengths() const;
   INLINE PTA_int get_lengths() const;
 
 
-  virtual int get_num_vertices_per_prim() const=0;
-  virtual int get_num_more_vertices_than_components() const=0;
-  virtual bool uses_components() const=0;
+  virtual int get_num_vertices_per_prim() const;
+  virtual int get_num_more_vertices_than_components() const;
+  virtual bool uses_components() const;
 
 
   INLINE int get_num_vertices() const;
   INLINE int get_num_vertices() const;
 
 
   // Returns the length of the indicated primitive.  Often this is the
   // Returns the length of the indicated primitive.  Often this is the
   // same for all primitives in the Geom.  However, geoms which use
   // same for all primitives in the Geom.  However, geoms which use
   // the lengths array will redefine this appropriately.
   // the lengths array will redefine this appropriately.
-  virtual int get_length(int prim) const=0;
+  virtual int get_length(int prim) const;
 
 
   virtual Geom *explode() const;
   virtual Geom *explode() const;
   virtual PTA_ushort get_tris() const;
   virtual PTA_ushort get_tris() const;
@@ -223,7 +223,7 @@ public:
   INLINE const Normalf &get_next_normal(NormalIterator &niterator) const;
   INLINE const Normalf &get_next_normal(NormalIterator &niterator) const;
 
 
   INLINE TexCoordIterator make_texcoord_iterator() const;
   INLINE TexCoordIterator make_texcoord_iterator() const;
-  INLINE TexCoordIterator make_texcoord_iterator(const TexCoordName *texcoord_name) const;
+  INLINE TexCoordIterator make_texcoord_iterator(const InternalName *texcoord_name) const;
   INLINE const TexCoordf &get_next_texcoord(TexCoordIterator &tciterator) const;
   INLINE const TexCoordf &get_next_texcoord(TexCoordIterator &tciterator) const;
   void setup_multitexcoord_iterator(MultiTexCoordIterator &iterator,
   void setup_multitexcoord_iterator(MultiTexCoordIterator &iterator,
                                     const ActiveTextureStages &active_stages,
                                     const ActiveTextureStages &active_stages,
@@ -245,8 +245,8 @@ public:
   virtual void config();
   virtual void config();
 
 
   // Immediate mode drawing functions - issue graphics commands
   // Immediate mode drawing functions - issue graphics commands
-  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc) = 0;
-  virtual void print_draw_immediate() const = 0;
+  virtual void draw_immediate(GraphicsStateGuardianBase *gsg, GeomContext *gc);
+  virtual void print_draw_immediate() const;
 
 
   void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
   void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
                          bool &found_any) const;
                          bool &found_any) const;
@@ -277,7 +277,7 @@ protected:
 
 
   // A pmap, not a phash_map, to save space because it will probably
   // A pmap, not a phash_map, to save space because it will probably
   // have only one element.
   // have only one element.
-  typedef pmap<CPT(TexCoordName), TexCoordDef> TexCoordsByName;
+  typedef pmap<CPT(InternalName), TexCoordDef> TexCoordsByName;
   TexCoordsByName _texcoords_by_name;
   TexCoordsByName _texcoords_by_name;
 
 
   // Functions to extract component values, one at a time.
   // Functions to extract component values, one at a time.
@@ -286,7 +286,7 @@ protected:
   GetNextColor *_get_color;
   GetNextColor *_get_color;
   GetNextTexCoord *_get_texcoord;
   GetNextTexCoord *_get_texcoord;
 
 
-  // temporary storage until complete_pointers fills in _texcoords_by_name's TexCoordName *
+  // temporary storage until complete_pointers fills in _texcoords_by_name's InternalName *
   typedef pvector<TexCoordDef *> TexCoordDefSet;
   typedef pvector<TexCoordDef *> TexCoordDefSet;
   TexCoordDefSet _temp_texcoord_set;
   TexCoordDefSet _temp_texcoord_set;
 
 

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

@@ -11,4 +11,14 @@
 #include "geomTri.cxx"
 #include "geomTri.cxx"
 #include "geomTrifan.cxx"
 #include "geomTrifan.cxx"
 #include "geomTristrip.cxx"
 #include "geomTristrip.cxx"
-
+#include "qpgeom.cxx"
+#include "qpgeomMunger.cxx"
+#include "qpgeomPrimitive.cxx"
+#include "qpgeomTriangles.cxx"
+#include "qpgeomTristrips.cxx"
+#include "qpgeomTrifans.cxx"
+#include "qpgeomVertexArrayFormat.cxx"
+#include "qpgeomVertexData.cxx"
+#include "qpgeomVertexDataType.cxx"
+#include "qpgeomVertexFormat.cxx"
+#include "qpgeomVertexIterator.cxx"

+ 1 - 1
panda/src/gobj/gobj_composite2.cxx

@@ -2,6 +2,7 @@
 #include "config_gobj.cxx"
 #include "config_gobj.cxx"
 #include "drawable.cxx"
 #include "drawable.cxx"
 #include "geomContext.cxx"
 #include "geomContext.cxx"
+#include "internalName.cxx"
 #include "material.cxx"
 #include "material.cxx"
 #include "materialPool.cxx"
 #include "materialPool.cxx"
 #include "orthographicLens.cxx"
 #include "orthographicLens.cxx"
@@ -13,5 +14,4 @@
 #include "texture.cxx"
 #include "texture.cxx"
 #include "textureContext.cxx"
 #include "textureContext.cxx"
 #include "texturePool.cxx"
 #include "texturePool.cxx"
-#include "texCoordName.cxx"
 #include "textureStage.cxx"
 #include "textureStage.cxx"

+ 185 - 0
panda/src/gobj/internalName.I

@@ -0,0 +1,185 @@
+// Filename: internalName.I
+// Created by:  masad (15Jul04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: InternalName::make
+//       Access: Published, Static
+//  Description: The public interface for constructing an InternalName
+//               pointer.  This will return a new InternalName
+//               representing the indicated name, if this is the first
+//               time the particular name has been requested; if the
+//               name is already in use, it will return the existing
+//               pointer.
+//
+//               If the string contains the '.' character, the string
+//               will be divided at the dots and the so-defined
+//               hierarchy of names will be registered.  This is
+//               handled transparently.
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+make(const string &name) {
+  return get_root()->append(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_parent
+//       Access: Published
+//  Description: Return the parent of this InternalName.  All names
+//               have a parent, except the root name.
+////////////////////////////////////////////////////////////////////
+INLINE InternalName *InternalName::
+get_parent() const {
+  return _parent;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_basename
+//       Access: Published
+//  Description: Return the name represented by just this particular
+//               InternalName object, ignoring its parents names.
+//               This is everything after the rightmost dot.
+////////////////////////////////////////////////////////////////////
+INLINE const string &InternalName::
+get_basename() const {
+  return _basename;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_root
+//       Access: Published, Static
+//  Description: Returns the standard root InternalName.  This is the
+//               root of all other InternalNames.  It has no name
+//               itself, and it is the only InternalName with no
+//               parent.
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_root() {
+  if (_root == (InternalName *)NULL) {
+    _root = new InternalName(NULL, "");
+  }
+  return _root;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_error
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "error".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_error() {
+  if (_error == (InternalName *)NULL) {
+    _error = InternalName::make("error");
+  }
+  return _error;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_vertex
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "vertex".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_vertex() {
+  if (_vertex == (InternalName *)NULL) {
+    _vertex = InternalName::make("vertex");
+  }
+  return _vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_normal
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "normal".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_normal() {
+  if (_normal == (InternalName *)NULL) {
+    _normal = InternalName::make("normal");
+  }
+  return _normal;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_tangent
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "tangent".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_tangent() {
+  if (_tangent == (InternalName *)NULL) {
+    _tangent = InternalName::make("tangent");
+  }
+  return _tangent;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_binormal
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "binormal".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_binormal() {
+  if (_binormal == (InternalName *)NULL) {
+    _binormal = InternalName::make("binormal");
+  }
+  return _binormal;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_texcoord
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "texcoord".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_texcoord() {
+  if (_texcoord == (InternalName *)NULL) {
+    _texcoord = InternalName::make("texcoord");
+  }
+  return _texcoord;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_texcoord_name
+//       Access: Published, Static
+//  Description: Returns the InternalName "texcoord.name", where name
+//               is the supplied string.  This, by convention,
+//               represents the named texture coordinate set.
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_texcoord_name(const string &name) {
+  return get_texcoord()->append(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_color
+//       Access: Published, Static
+//  Description: Returns the standard InternalName "color".
+////////////////////////////////////////////////////////////////////
+INLINE PT(InternalName) InternalName::
+get_color() {
+  if (_color == (InternalName *)NULL) {
+    _color = InternalName::make("color");
+  }
+  return _color;
+}
+
+INLINE ostream &
+operator << (ostream &out, const InternalName &tcn) {
+  tcn.output(out);
+  return out;
+}

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

@@ -0,0 +1,231 @@
+// Filename: internalName.cxx
+// Created by: masad (15Jul04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "pandabase.h"
+#include "internalName.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+#include "preparedGraphicsObjects.h"
+
+PT(InternalName) InternalName::_root;
+PT(InternalName) InternalName::_error;
+PT(InternalName) InternalName::_default;
+PT(InternalName) InternalName::_vertex;
+PT(InternalName) InternalName::_normal;
+PT(InternalName) InternalName::_tangent;
+PT(InternalName) InternalName::_binormal;
+PT(InternalName) InternalName::_texcoord;
+PT(InternalName) InternalName::_color;
+
+TypeHandle InternalName::_type_handle;
+TypeHandle InternalName::_texcoord_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::Constructor
+//       Access: Private
+//  Description: Use make() to make a new InternalName instance.
+////////////////////////////////////////////////////////////////////
+InternalName::
+InternalName(InternalName *parent, const string &basename) :
+  _parent(parent),
+  _basename(basename)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::Destructor
+//       Access: Published, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+InternalName::
+~InternalName() {
+  if (_parent != (const InternalName *)NULL) {
+    NameTable::iterator ni = _parent->_name_table.find(_basename);
+    nassertv(ni != _parent->_name_table.end());
+    _parent->_name_table.erase(ni);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::append
+//       Access: Published
+//  Description: Constructs a new InternalName based on this name,
+//               with the indicated string following it.  This is a
+//               cheaper way to construct a hierarchical name than
+//               InternalName::make(parent->get_name() + ".basename").
+////////////////////////////////////////////////////////////////////
+PT(InternalName) InternalName::
+append(const string &name) {
+  if (name.empty()) {
+    return this;
+  }
+
+  size_t dot = name.rfind('.');
+  if (dot != string::npos) {
+    return append(name.substr(0, dot))->append(name.substr(dot + 1));
+  }
+
+  NameTable::iterator ni = _name_table.find(name);
+  if (ni != _name_table.end()) {
+    return (*ni).second;
+  }
+
+  PT(InternalName) internal_name = new InternalName(this, name);
+  _name_table[name] = internal_name;
+  return internal_name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::get_name
+//       Access: Published
+//  Description: Returns the complete name represented by the
+//               InternalName and all of its parents.
+////////////////////////////////////////////////////////////////////
+string InternalName::
+get_name() const {
+  if (_parent == get_root()) {
+    return _basename;
+
+  } else if (_parent == (InternalName *)NULL) {
+    return string();
+
+  } else {
+    return _parent->get_name() + "." + _basename;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void InternalName::
+output(ostream &out) const {
+  if (_parent == get_root()) {
+    out << _basename;
+
+  } else if (_parent == (InternalName *)NULL) {
+    out << "(root)";
+
+  } else {
+    _parent->output(out);
+    out << '.' << _basename;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::register_with_read_factory
+//       Access: Public, Static
+//  Description: Factory method to generate a InternalName object
+////////////////////////////////////////////////////////////////////
+void InternalName::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+  BamReader::get_factory()->register_factory(_texcoord_type_handle, make_texcoord_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::finalize
+//       Access: Public, Virtual
+//  Description: Method to ensure that any necessary clean up tasks
+//               that have to be performed by this object are performed
+////////////////////////////////////////////////////////////////////
+void InternalName::
+finalize() {
+  // Unref the pointer that we explicitly reffed in make_from_bam().
+  unref();
+
+  // We should never get back to zero after unreffing our own count,
+  // because we expect to have been stored in a pointer somewhere.  If
+  // we do get to zero, it's a memory leak; the way to avoid this is
+  // to call unref_delete() above instead of unref(), but this is
+  // dangerous to do from within a virtual function.
+  nassertv(get_ref_count() != 0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type InternalName is encountered
+//               in the Bam file.  It should create the InternalName
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *InternalName::
+make_from_bam(const FactoryParams &params) {
+  // The process of making a InternalName is slightly
+  // different than making other Writable objects.
+  // That is because all creation of InternalNames should
+  // be done through the make() constructor.
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+
+  // The name is the only thing written to the data stream.
+  string name = scan.get_string();
+
+  // Make a new InternalName with that name (or get the previous one
+  // if there is one already).
+  PT(InternalName) me = make(name);
+
+  // But now we have a problem, since we have to hold the reference
+  // count and there's no way to return a TypedWritable while still
+  // holding the reference count!  We work around this by explicitly
+  // upping the count, and also setting a finalize() callback to down
+  // it later.
+  me->ref();
+  manager->register_finalize(me);
+  
+  return me.p();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::make_texcoord_from_bam
+//       Access: Protected, Static
+//  Description: This is a temporary method; it exists only to support
+//               old bam files (4.11 through 4.17) generated before we
+//               renamed this class from TexCoordName to InternalName.
+////////////////////////////////////////////////////////////////////
+TypedWritable *InternalName::
+make_texcoord_from_bam(const FactoryParams &params) {
+  DatagramIterator scan;
+  BamReader *manager;
+  parse_params(params, scan, manager);
+
+  string name = scan.get_string();
+  PT(InternalName) me = get_texcoord_name(name);
+
+  me->ref();
+  manager->register_finalize(me);
+  
+  return me.p();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: InternalName::write_datagram
+//       Access: Public
+//  Description: Function to write the important information in
+//               the particular object to a Datagram
+////////////////////////////////////////////////////////////////////
+void InternalName::
+write_datagram(BamWriter *manager, Datagram &me) {
+  me.add_string(get_name());
+}
+

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

@@ -0,0 +1,129 @@
+// Filename: internalName.h
+// Created by:  drose (15Jul04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 INTERNALNAME_H
+#define INTERNALNAME_H
+
+#include "pandabase.h"
+
+#include "typedWritableReferenceCount.h"
+#include "pointerTo.h"
+#include "pmap.h"
+
+class FactoryParams;
+
+////////////////////////////////////////////////////////////////////
+//       Class : InternalName
+// Description : Encodes a string name in a hash table, mapping it to
+//               a pointer.  This is used to tokenify names so they
+//               may be used efficiently in low-level Panda
+//               structures, for instance to differentiate the
+//               multiple sets of texture coordinates that might be
+//               stored on a Geom.
+//
+//               InternalNames are hierarchical, with the '.' used by
+//               convention as a separator character.  You can
+//               construct a single InternalName as a composition of
+//               one or more other names, or by giving it a source
+//               string directly.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA InternalName : public TypedWritableReferenceCount {
+private:
+  InternalName(InternalName *parent, const string &basename);
+
+PUBLISHED:
+  virtual ~InternalName();
+  INLINE static PT(InternalName) make(const string &name);
+  PT(InternalName) append(const string &basename);
+
+  INLINE InternalName *get_parent() const;
+  string get_name() const;
+  INLINE const string &get_basename() const;
+
+  void output(ostream &out) const;
+
+  // Some predefined built-in names.
+  INLINE static PT(InternalName) get_root();
+  INLINE static PT(InternalName) get_error();
+  INLINE static PT(InternalName) get_vertex();
+  INLINE static PT(InternalName) get_normal();
+  INLINE static PT(InternalName) get_tangent();
+  INLINE static PT(InternalName) get_binormal();
+  INLINE static PT(InternalName) get_texcoord();
+  INLINE static PT(InternalName) get_texcoord_name(const string &name);
+  INLINE static PT(InternalName) get_color();
+
+private:
+  PT(InternalName) _parent;
+  string _basename;
+
+  typedef phash_map<string, InternalName *, string_hash> NameTable;
+  NameTable _name_table;
+
+  static PT(InternalName) _root;
+  static PT(InternalName) _error;
+  static PT(InternalName) _default;
+  static PT(InternalName) _vertex;
+  static PT(InternalName) _normal;
+  static PT(InternalName) _tangent;
+  static PT(InternalName) _binormal;
+  static PT(InternalName) _texcoord;
+  static PT(InternalName) _color;
+  
+public:
+  // Datagram stuff
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &me);
+
+  virtual void finalize();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  static TypedWritable *make_texcoord_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "InternalName",
+                  TypedWritableReferenceCount::get_class_type());
+    // The _texcoord_type_handle is defined only to support older bam
+    // files, generated before we renamed the type to InternalName.
+    register_type(_texcoord_type_handle, "TexCoordName",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+  static TypeHandle _texcoord_type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const InternalName &tcn);
+
+#include "internalName.I"
+
+#endif
+
+
+  

+ 114 - 0
panda/src/gobj/qpgeom.I

@@ -0,0 +1,114 @@
+// Filename: qpgeom.I
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeom::get_vertex_data
+//       Access: Published
+//  Description: Returns a const pointer to the GeomVertexData,
+//               for application code to directly examine (but not
+//               modify) the geom's underlying data.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexData) qpGeom::
+get_vertex_data() const {
+  CDReader cdata(_cycler);
+  return cdata->_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::get_num_primitives
+//       Access: Published
+//  Description: Returns the number of GeomPrimitive objects stored
+//               within the Geom, each of which represents a number of
+//               primitives of a particular type.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeom::
+get_num_primitives() const {
+  CDReader cdata(_cycler);
+  return cdata->_primitives.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::get_primitive
+//       Access: Published
+//  Description: Returns a const pointer to the ith GeomPrimitive
+//               object stored within the Geom.  Use this call only to
+//               inspect the ith object; use modify_primitive() or
+//               set_primitive() if you want to modify it.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomPrimitive *qpGeom::
+get_primitive(int i) const {
+  CDReader cdata(_cycler);
+  nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL);
+  return cdata->_primitives[i];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::modify_primitive
+//       Access: Published
+//  Description: Returns a modifiable pointer to the ith GeomPrimitive
+//               object stored within the Geom, so application code
+//               can directly manipulate the properties of this
+//               primitive.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomPrimitive *qpGeom::
+modify_primitive(int i) {
+  CDWriter cdata(_cycler);
+  nassertr(i >= 0 && i < (int)cdata->_primitives.size(), NULL);
+  return cdata->_primitives[i];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::set_primitive
+//       Access: Published
+//  Description: Replaces the ith GeomPrimitive object stored within
+//               the Geom with the new object.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeom::
+set_primitive(int i, qpGeomPrimitive *primitive) {
+  CDWriter cdata(_cycler);
+  nassertv(i >= 0 && i < (int)cdata->_primitives.size());
+  cdata->_primitives[i] = primitive;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CData::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE qpGeom::CData::
+CData() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CData::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE qpGeom::CData::
+CData(const qpGeom::CData &copy) :
+  _data(copy._data),
+  _primitives(copy._primitives)
+{
+}
+
+INLINE ostream &
+operator << (ostream &out, const qpGeom &obj) {
+  obj.output(out);
+  return out;
+}

+ 395 - 0
panda/src/gobj/qpgeom.cxx

@@ -0,0 +1,395 @@
+// Filename: qpgeom.cxx
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeom.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeom::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeom::
+qpGeom() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeom::
+qpGeom(const qpGeom &copy) :
+  /*
+  TypedWritableReferenceCount(copy),
+  BoundedObject(copy),
+  */
+  Geom(copy),
+  _cycler(copy._cycler)  
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::Copy Assignment Operator
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+operator = (const qpGeom &copy) {
+  /*
+  TypedWritableReferenceCount::operator = (copy);
+  BoundedObject::operator = (copy);
+  */
+  Geom::operator = (copy);
+  _cycler = copy._cycler;
+  mark_bound_stale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeom::
+~qpGeom() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::make_copy
+//       Access: Published, Virtual
+//  Description: Temporarily redefined from Geom base class.
+////////////////////////////////////////////////////////////////////
+Geom *qpGeom::
+make_copy() const {
+  return new qpGeom(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::modify_vertex_data
+//       Access: Published
+//  Description: Returns a modifiable pointer to the GeomVertexData,
+//               so that application code may directly maniuplate the
+//               geom's underlying data.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomVertexData) qpGeom::
+modify_vertex_data() {
+  // Perform copy-on-write: if the reference count on the vertex data
+  // is greater than 1, assume some other Geom has the same pointer,
+  // so make a copy of it first.
+
+  CDWriter cdata(_cycler);
+  if (cdata->_data->get_ref_count() > 1) {
+    cdata->_data = new qpGeomVertexData(*cdata->_data);
+  }
+  mark_bound_stale();
+  return cdata->_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::set_vertex_data
+//       Access: Published
+//  Description: Replaces the Geom's underlying vertex data table with
+//               a completely new table.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+set_vertex_data(PT(qpGeomVertexData) data) {
+  CDWriter cdata(_cycler);
+  cdata->_data = data;
+  mark_bound_stale();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::add_primitive
+//       Access: Published
+//  Description: Adds a new GeomPrimitive structure to the Geom
+//               object.  This specifies a particular subset of
+//               vertices that are used to define geometric primitives
+//               of the indicated type.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+add_primitive(qpGeomPrimitive *primitive) {
+  CDWriter cdata(_cycler);
+  cdata->_primitives.push_back(primitive);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::remove_primitive
+//       Access: Published
+//  Description: Removes the ith primitive from the list.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+remove_primitive(int i) {
+  CDWriter cdata(_cycler);
+  nassertv(i >= 0 && i < (int)cdata->_primitives.size());
+  cdata->_primitives.erase(cdata->_primitives.begin() + i);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::clear_primitives
+//       Access: Published
+//  Description: Removes all the primitives from the Geom object (but
+//               keeps the same table of vertices).  You may then
+//               re-add primitives one at a time via calls to
+//               add_primitive().
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+clear_primitives() {
+  CDWriter cdata(_cycler);
+  cdata->_primitives.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+output(ostream &out) const {
+  CDReader cdata(_cycler);
+
+  // Get a list of the primitive types contained within this object.
+  pset<TypeHandle> types;
+  Primitives::const_iterator pi;
+  for (pi = cdata->_primitives.begin(); 
+       pi != cdata->_primitives.end();
+       ++pi) {
+    types.insert((*pi)->get_type());
+  }
+
+  out << "Geom [";
+  pset<TypeHandle>::iterator ti;
+  for (ti = types.begin(); ti != types.end(); ++ti) {
+    out << " " << (*ti);
+  }
+  out << " ], " << cdata->_data->get_num_vertices() << " vertices.";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::write
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+write(ostream &out, int indent_level) const {
+  CDReader cdata(_cycler);
+
+  // Get a list of the primitive types contained within this object.
+  Primitives::const_iterator pi;
+  for (pi = cdata->_primitives.begin(); 
+       pi != cdata->_primitives.end();
+       ++pi) {
+    (*pi)->write(out, cdata->_data, indent_level);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::draw
+//       Access: Public
+//  Description: Actually draws the Geom with the indicated GSG.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+draw(GraphicsStateGuardianBase *gsg) const {
+  //  PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
+  CDReader cdata(_cycler);
+
+  gsg->begin_draw_primitives(cdata->_data);
+
+  Primitives::const_iterator pi;
+  for (pi = cdata->_primitives.begin(); 
+       pi != cdata->_primitives.end();
+       ++pi) {
+    (*pi)->draw(gsg);
+  }
+
+  gsg->end_draw_primitives();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::recompute_bound
+//       Access: Protected, Virtual
+//  Description: Recomputes the dynamic bounding volume for this Geom.
+//               This includes all of the vertices.
+////////////////////////////////////////////////////////////////////
+BoundingVolume *qpGeom::
+recompute_bound() {
+  // First, get ourselves a fresh, empty bounding volume.
+  BoundingVolume *bound = BoundedObject::recompute_bound();
+  nassertr(bound != (BoundingVolume*)0L, bound);
+
+  GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
+
+  // Now actually compute the bounding volume by putting it around all
+  // of our vertices.
+  CDReader cdata(_cycler);
+
+  const qpGeomVertexFormat *format = cdata->_data->get_format();
+
+  int array_index = format->get_array_with(InternalName::get_vertex());
+  if (array_index < 0) {
+    // No vertex data.
+    return bound;
+  }
+
+  const qpGeomVertexArrayFormat *array_format = format->get_array(array_index);
+  const qpGeomVertexDataType *data_type = 
+    array_format->get_data_type(InternalName::get_vertex());
+
+  int stride = array_format->get_stride();
+  int start = data_type->get_start();
+  int num_components = data_type->get_num_components();
+
+  CPTA_uchar array_data = cdata->_data->get_array_data(array_index);
+
+  if (stride == 3 * sizeof(PN_float32) && start == 0 && num_components == 3 &&
+      (array_data.size() % stride) == 0) {
+    // Here's an easy special case: it's a standalone table of vertex
+    // positions, with nothing else in the middle, so we can use
+    // directly as an array of LPoint3f's.
+    const LPoint3f *vertices_begin = (const LPoint3f *)&array_data[0];
+    const LPoint3f *vertices_end = (const LPoint3f *)&array_data[array_data.size()];
+    gbv->around(vertices_begin, vertices_end);
+
+  } else {
+    // Otherwise, we have to copy the vertex positions out one at time.
+    pvector<LPoint3f> vertices;
+
+    size_t p = start;
+    while (p + stride <= array_data.size()) {
+      const PN_float32 *v = (const PN_float32 *)&array_data[p];
+
+      LPoint3f vertex;
+      qpGeomVertexData::to_vec3(vertex, v, num_components);
+
+      vertices.push_back(vertex);
+      p += stride;
+    }
+
+    const LPoint3f *vertices_begin = &vertices[0];
+    const LPoint3f *vertices_end = vertices_begin + vertices.size();
+
+    gbv->around(vertices_begin, vertices_end);
+  }
+
+  return bound;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  TypedWritable::write_datagram(manager, dg);
+
+  manager->write_cdata(dg, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeom::
+make_from_bam(const FactoryParams &params) {
+  qpGeom *object = new qpGeom;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  TypedWritable::fillin(scan, manager);
+
+  manager->read_cdata(scan, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CData::make_copy
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData *qpGeom::CData::
+make_copy() const {
+  return new CData(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CData::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeom::CData::
+write_datagram(BamWriter *manager, Datagram &dg) const {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CData::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int qpGeom::CData::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = CycleData::complete_pointers(p_list, manager);
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::CData::fillin
+//       Access: Public, Virtual
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeom::CData::
+fillin(DatagramIterator &scan, BamReader *manager) {
+}

+ 139 - 0
panda/src/gobj/qpgeom.h

@@ -0,0 +1,139 @@
+// Filename: qpgeom.h
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOM_H
+#define qpGEOM_H
+
+#include "pandabase.h"
+#include "typedWritableReferenceCount.h"
+#include "boundedObject.h"
+#include "cycleData.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "pipelineCycler.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomPrimitive.h"
+#include "pointerTo.h"
+#include "geom.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeom
+// Description : A container for geometry primitives.  This class
+//               associates one or more GeomPrimitive objects with a
+//               table of vertices defined by a GeomVertexData object.
+//               All of the primitives stored in a particular Geom are
+//               drawn from the same set of vertices (each primitive
+//               uses a subset of all of the vertices in the table),
+//               and all of them must be rendered at the same time, in
+//               the same graphics state.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeom /* : public TypedWritableReferenceCount, public BoundedObject */
+// We temporarily inherit from Geom, merely so we can store this
+// pointer where a Geom should go, while we have both implementations
+// in the codebase.  We pick up some additional cruft from Geom that
+// we're not really using.
+  : public Geom
+{
+PUBLISHED:
+  qpGeom();
+  qpGeom(const qpGeom &copy);
+  void operator = (const qpGeom &copy);
+  virtual ~qpGeom();
+
+  // Temporary.
+  virtual Geom *make_copy() const;
+
+  INLINE CPT(qpGeomVertexData) get_vertex_data() const;
+  PT(qpGeomVertexData) modify_vertex_data();
+  void set_vertex_data(PT(qpGeomVertexData) data);
+
+  INLINE int get_num_primitives() const;
+  INLINE const qpGeomPrimitive *get_primitive(int i) const;
+  INLINE qpGeomPrimitive *modify_primitive(int i);
+  INLINE void set_primitive(int i, qpGeomPrimitive *primitive);
+  void add_primitive(qpGeomPrimitive *primitive);
+  void remove_primitive(int i);
+  void clear_primitives();
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level = 0) const;
+
+public:
+  void draw(GraphicsStateGuardianBase *gsg) const;
+
+protected:
+  virtual BoundingVolume *recompute_bound();
+
+private:
+  typedef pvector<PT(qpGeomPrimitive) > Primitives;
+
+  // This is the data that must be cycled between pipeline stages.
+  class EXPCL_PANDA CData : public CycleData {
+  public:
+    INLINE CData();
+    INLINE CData(const CData &copy);
+    virtual CycleData *make_copy() const;
+    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
+    virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
+    virtual void fillin(DatagramIterator &scan, BamReader *manager);
+
+    PT(qpGeomVertexData) _data;
+    Primitives _primitives;
+  };
+
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    /*TypedWritableReferenceCount::init_type();
+      BoundedObject::init_type();*/
+    Geom::init_type();
+    register_type(_type_handle, "qpGeom",
+                  Geom::get_class_type()
+                  /*TypedWritableReferenceCount::get_class_type(),
+                    BoundedObject::get_class_type()*/);
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const qpGeom &obj);
+
+#include "qpgeom.I"
+
+#endif

+ 113 - 0
panda/src/gobj/qpgeomMunger.I

@@ -0,0 +1,113 @@
+// Filename: qpgeomMunger.I
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomMunger::is_registered
+//       Access: Published
+//  Description: Returns true if this munger has been registered,
+//               false if it has not.  It may not be used for a Geom
+//               until it has been registered, but once registered, it
+//               may no longer be modified.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomMunger::
+is_registered() const {
+  return _is_registered;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::register_munger
+//       Access: Published, Static
+//  Description: Adds the indicated munger to the registry, if there
+//               is not an equivalent munger already there; in either
+//               case, returns the pointer to the equivalent munger
+//               now in the registry.
+//
+//               This must be called before a munger may be used in a
+//               Geom.  After this call, you should discard the
+//               original pointer you passed in (which may or may not
+//               now be invalid) and let its reference count decrement
+//               normally; you should use only the returned value from
+//               this point on.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomMunger) qpGeomMunger::
+register_munger(qpGeomMunger *munger) {
+  return get_registry()->register_munger(munger);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::compare_to
+//       Access: Public
+//  Description: Provides an arbitrary ordering among all unique
+//               GeomMungers, so we can store the essentially
+//               different ones in a big set and throw away the rest.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomMunger::
+compare_to(const qpGeomMunger &other) const {
+  // First, we compare the types; if they are of different types then
+  // they sort differently.
+  TypeHandle type = get_type();
+  TypeHandle other_type = other.get_type();
+  if (type != other_type) {
+    return type.get_index() - other_type.get_index();
+  }
+
+  // We only call compare_to_impl() if they have the same type.
+  return compare_to_impl(&other);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::munge_data
+//       Access: Public
+//  Description: Given a source GeomVertexData, converts it if
+//               necessary to the appropriate data for rendering.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexData) qpGeomMunger::
+munge_data(const qpGeomVertexData *data) const {
+  // We cast away the const pointer, because do_munge_data() needs to
+  // update caches and stuff, but we trust it not to change any
+  // user-definable parameters.
+  return ((qpGeomMunger *)this)->do_munge_data(data);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::munge_format
+//       Access: Public
+//  Description: Given a source GeomVertexFormat, converts it if
+//               necessary to the appropriate format for rendering.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexFormat) qpGeomMunger::
+munge_format(const qpGeomVertexFormat *format) const {
+  // We cast away the const pointer, because do_munge_format() needs
+  // to update caches and stuff, but we trust it not to change any
+  // user-definable parameters.
+  return ((qpGeomMunger *)this)->do_munge_format(format);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::get_registry
+//       Access: Private
+//  Description: Returns the global registry object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomMunger::Registry *qpGeomMunger::
+get_registry() {
+  if (_registry == (Registry *)NULL) {
+    make_registry();
+  }
+  return _registry;
+}

+ 282 - 0
panda/src/gobj/qpgeomMunger.cxx

@@ -0,0 +1,282 @@
+// Filename: qpgeomMunger.cxx
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomMunger.h"
+
+qpGeomMunger::Registry *qpGeomMunger::_registry = NULL;
+TypeHandle qpGeomMunger::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomMunger::
+qpGeomMunger() :
+  _is_registered(false)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomMunger::
+~qpGeomMunger() {
+  if (is_registered()) {
+    get_registry()->unregister_munger(this);
+  }
+  nassertv(_formats.empty());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::remove_format
+//       Access: Public
+//  Description: Removes a prepared GeomVertexFormat from the cache.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+remove_format(const qpGeomVertexFormat *format) {
+  // If this assertion is triggered, maybe we accidentally deleted a
+  // GeomVertexFormat while we were in the process of unregistering,
+  // causing a recursive re-entry.
+  nassertv(_is_registered);
+
+  Formats::iterator fi;
+  fi = _formats.find(format);
+  nassertv(fi != _formats.end());
+
+  CPT(qpGeomVertexFormat) derived_format = (*fi).second;
+  _formats.erase(fi);
+
+  // We need to unref the derived format, if we reffed it earlier.
+  if (derived_format != format) {
+    derived_format->unref();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::remove_data
+//       Access: Public
+//  Description: Removes a prepared GeomVertexData from the cache.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+remove_data(const qpGeomVertexData *data) {
+  // If this assertion is triggered, maybe we accidentally deleted a
+  // GeomVertexData while we were in the process of unregistering,
+  // causing a recursive re-entry.
+  nassertv(_is_registered);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::do_munge_data
+//       Access: Protected
+//  Description: The protected implementation of munge_data().  This
+//               exists just to cast away the const pointer.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexData) qpGeomMunger::
+do_munge_data(const qpGeomVertexData *data) {
+  nassertr(_is_registered, NULL);
+
+  CPT(qpGeomVertexFormat) orig_format = data->get_format();
+  CPT(qpGeomVertexFormat) new_format = munge_format(orig_format);
+
+  if (new_format == orig_format) {
+    // Trivial case.
+    return data;
+  }
+
+  return data->convert_to(new_format);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::do_munge_format
+//       Access: Protected
+//  Description: The protected implementation of munge_format().  This
+//               exists just to cast away the const pointer.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) qpGeomMunger::
+do_munge_format(const qpGeomVertexFormat *format) {
+  nassertr(_is_registered, NULL);
+  nassertr(format->is_registered(), NULL);
+
+  Formats::iterator fi;
+  fi = _formats.find(format);
+  if (fi != _formats.end()) {
+    // This format was previously munged, so the answer will be the
+    // same.
+    return (*fi).second;
+  }
+
+  // We have to munge this format for the first time.
+  CPT(qpGeomVertexFormat) derived_format = munge_format_impl(format);
+  nassertr(derived_format->is_registered(), NULL);
+
+  // Store the answer in the map, so we can quickly get it next time.
+  bool inserted = _formats.insert(Formats::value_type(format, derived_format)).second;
+  nassertr(inserted, NULL);
+
+  // Tell the source format that we have its pointer.
+  inserted = ((qpGeomVertexFormat *)format)->_mungers.insert(this).second;
+  nassertr(inserted, NULL);
+
+  // We also want to keep a reference count on the derived format, but
+  // only if it is actually a different pointer from the original
+  // format--otherwise it would cause a self-referential reference
+  // count.
+  if (derived_format != format) {
+    derived_format->ref();
+  }
+
+  return derived_format;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::munge_format_impl
+//       Access: Protected, Virtual
+//  Description: Given a source GeomVertexFormat, converts it if
+//               necessary to the appropriate format for rendering.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) qpGeomMunger::
+munge_format_impl(const qpGeomVertexFormat *orig) {
+  return orig;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::compare_to_impl
+//       Access: Protected, Virtual
+//  Description: Called to compare two GeomMungers who are known to be
+//               of the same type, for an apples-to-apples comparison.
+//               This will never be called on two pointers of a
+//               different type.
+////////////////////////////////////////////////////////////////////
+int qpGeomMunger::
+compare_to_impl(const qpGeomMunger *other) const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::make_registry
+//       Access: Private
+//  Description: Returns the global registry object.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+make_registry() {
+  if (_registry == (Registry *)NULL) {
+    _registry = new Registry;
+  }
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::do_register
+//       Access: Private
+//  Description: Called internally when the munger is registered.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+do_register() {
+  nassertv(!_is_registered);
+  nassertv(_formats.empty());
+
+  _is_registered = true;
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::do_unregister
+//       Access: Private
+//  Description: Called internally when the munger is unregistered.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::
+do_unregister() {
+  nassertv(_is_registered);
+  _is_registered = false;
+
+  // Unregistering means we should blow away the cache.
+  Formats::iterator fi;
+  for (fi = _formats.begin(); fi != _formats.end(); ++fi) {
+    const qpGeomVertexFormat *format = (*fi).first;
+    CPT(qpGeomVertexFormat) derived_format = (*fi).second;
+
+    size_t num_erased = ((qpGeomVertexFormat *)format)->_mungers.erase(this);
+    nassertv(num_erased == 1);
+
+    if (derived_format != format) {
+      derived_format->unref();
+    }
+  }
+  _formats.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Registry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomMunger::Registry::
+Registry() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Registry::register_munger
+//       Access: Public
+//  Description: Adds the indicated munger to the registry, if there
+//               is not an equivalent munger already there; in either
+//               case, returns the pointer to the equivalent munger
+//               now in the registry.
+//
+//               This must be called before a munger may be used in a
+//               Geom.  After this call, you should discard the
+//               original pointer you passed in (which may or may not
+//               now be invalid) and let its reference count decrement
+//               normally; you should use only the returned value from
+//               this point on.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomMunger) qpGeomMunger::Registry::
+register_munger(qpGeomMunger *munger) {
+  if (munger->is_registered()) {
+    return munger;
+  }
+
+  // Save the incoming pointer in a local PointerTo, so that if it has
+  // a zero reference count and is not added into the map below, it
+  // will be automatically deleted when this function returns.
+  PT(qpGeomMunger) pt_munger = munger;
+
+  Mungers::iterator mi = _mungers.insert(munger).first;
+  qpGeomMunger *new_munger = (*mi);
+  if (!new_munger->is_registered()) {
+    new_munger->do_register();
+  }
+
+  return new_munger;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomMunger::Registry::unregister_munger
+//       Access: Public
+//  Description: Removes the indicated munger from the registry.
+//               Normally this should not be done until the munger is
+//               destructing.
+////////////////////////////////////////////////////////////////////
+void qpGeomMunger::Registry::
+unregister_munger(qpGeomMunger *munger) {
+  nassertv(munger->is_registered());
+  Mungers::iterator mi = _mungers.find(munger);
+  nassertv(mi != _mungers.end());
+  _mungers.erase(mi);
+  munger->do_unregister();
+}

+ 121 - 0
panda/src/gobj/qpgeomMunger.h

@@ -0,0 +1,121 @@
+// Filename: qpgeomMunger.h
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMMUNGER_H
+#define qpGEOMMUNGER_H
+
+#include "pandabase.h"
+#include "typedReferenceCount.h"
+#include "qpgeomVertexFormat.h"
+#include "indirectCompareTo.h"
+#include "pmap.h"
+#include "pset.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomMunger
+// Description : Objects of this class are used to convert vertex data
+//               from a Geom into a format suitable for passing to the
+//               rendering backend.  Typically, the rendering backend
+//               will create a specialization of this class to handle
+//               its particular needs (e.g. DXGeomMunger).  This class
+//               is necessary because DirectX and OpenGL have somewhat
+//               different requirements for vertex format.
+//
+//               This also performs runtime application of state
+//               changes to the vertex data; for instance, by scaling
+//               all of the color values in response to a
+//               ColorScaleAttrib.
+//
+//               A GeomMunger must be registered before it can be
+//               used, and once registered, the object is constant and
+//               cannot be changed.  All registered GeomMungers that
+//               perform the same operation will have the same
+//               pointer.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomMunger : public TypedReferenceCount {
+public:
+  qpGeomMunger();
+  virtual ~qpGeomMunger();
+
+  INLINE bool is_registered() const;
+  INLINE static CPT(qpGeomMunger) register_munger(qpGeomMunger *munger);
+
+  INLINE CPT(qpGeomVertexFormat) munge_format(const qpGeomVertexFormat *format) const;
+  void remove_format(const qpGeomVertexFormat *format);
+
+  INLINE CPT(qpGeomVertexData) munge_data(const qpGeomVertexData *data) const;
+  void remove_data(const qpGeomVertexData *data);
+
+public:
+  INLINE int compare_to(const qpGeomMunger &other) const;
+
+protected:
+  CPT(qpGeomVertexFormat) do_munge_format(const qpGeomVertexFormat *format);
+  CPT(qpGeomVertexData) do_munge_data(const qpGeomVertexData *data);
+
+  virtual CPT(qpGeomVertexFormat) munge_format_impl(const qpGeomVertexFormat *orig);
+  virtual int compare_to_impl(const qpGeomMunger *other) const;
+
+private:
+  class Registry;
+  INLINE static Registry *get_registry();
+  static void make_registry();
+
+  void do_register();
+  void do_unregister();
+
+  typedef pmap<const qpGeomVertexFormat *, const qpGeomVertexFormat *> Formats;
+  Formats _formats;
+
+  bool _is_registered;
+  typedef pset<qpGeomMunger *, IndirectCompareTo<qpGeomMunger> > Mungers;
+  class Registry {
+  public:
+    Registry();
+    CPT(qpGeomMunger) register_munger(qpGeomMunger *munger);
+    void unregister_munger(qpGeomMunger *munger);
+
+    Mungers _mungers;
+  };
+
+  static Registry *_registry;
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedReferenceCount::init_type();
+    register_type(_type_handle, "qpGeomMunger",
+                  TypedReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "qpgeomMunger.I"
+
+#endif
+

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

@@ -0,0 +1,132 @@
+// Filename: qpgeomPrimitive.I
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomPrimitive::get_num_vertices
+//       Access: Published
+//  Description: Returns the number of vertex vertices used by all the
+//               primitives in this object.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_num_vertices() const {
+  CDReader cdata(_cycler);
+  return cdata->_vertices.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_vertex
+//       Access: Published
+//  Description: Returns the ith vertex index in the table.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_vertex(int i) const {
+  CDReader cdata(_cycler);
+  nassertr(i >= 0 && i < (int)cdata->_vertices.size(), -1);
+  return cdata->_vertices[i];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_vertices
+//       Access: Published
+//  Description: Returns a const pointer to the vertex index array so
+//               application code can read it directly.  Do not
+//               attempt to modify the returned array; use
+//               modify_vertices() or set_vertices() for this.
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_ushort qpGeomPrimitive::
+get_vertices() const {
+  CDReader cdata(_cycler);
+  return cdata->_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_vertices
+//       Access: Published
+//  Description: Returns a const pointer to the primitive lengths
+//               array so application code can read it directly.  Do
+//               not attempt to modify the returned array; use
+//               modify_lengths() or set_lengths() for this.
+//
+//               Note that simple primitive types, like triangles, do
+//               not have a lengths array: since all the primitives
+//               have the same number of vertices, it is not needed.
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_int qpGeomPrimitive::
+get_lengths() const {
+  CDReader cdata(_cycler);
+  return cdata->_lengths;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_min_vertex
+//       Access: Published
+//  Description: Returns the minimum vertex index number used by the
+//               primitives in this object.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_min_vertex() const {
+  CDReader cdata(_cycler);
+  if (!cdata->_got_minmax) {
+    ((qpGeomPrimitive *)this)->recompute_minmax();
+  }
+  return cdata->_min_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_max_vertex
+//       Access: Published
+//  Description: Returns the maximum vertex index number used by the
+//               primitives in this object.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomPrimitive::
+get_max_vertex() const {
+  CDReader cdata(_cycler);
+  if (!cdata->_got_minmax) {
+    ((qpGeomPrimitive *)this)->recompute_minmax();
+  }
+  return cdata->_max_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomPrimitive::CData::
+CData() :
+  _got_minmax(true),
+  _min_vertex(0),
+  _max_vertex(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomPrimitive::CData::
+CData(const qpGeomPrimitive::CData &copy) :
+  _vertices(copy._vertices),
+  _lengths(copy._lengths),
+  _got_minmax(copy._got_minmax),
+  _min_vertex(copy._min_vertex),
+  _max_vertex(copy._max_vertex)
+{
+}

+ 520 - 0
panda/src/gobj/qpgeomPrimitive.cxx

@@ -0,0 +1,520 @@
+// Filename: qpgeomPrimitive.cxx
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomPrimitive.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomVertexArrayFormat.h"
+#include "qpgeomVertexDataType.h"
+#include "internalName.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "indent.h"
+
+TypeHandle qpGeomPrimitive::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::
+qpGeomPrimitive() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::
+qpGeomPrimitive(const qpGeomPrimitive &copy) :
+  TypedWritableReferenceCount(copy),
+  _cycler(copy._cycler)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomPrimitive::
+~qpGeomPrimitive() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::add_vertex
+//       Access: Published
+//  Description: Adds the indicated vertex to the list of vertex
+//               indices used by the graphics primitive type.  To
+//               define primitive, you must call add_vertex() for each
+//               vertex of the new primitve, and then call
+//               close_primitive() after you have specified the last
+//               vertex of each primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+add_vertex(int vertex) {
+  unsigned short short_vertex = vertex;
+  nassertv((int)short_vertex == vertex);
+
+  CDWriter cdata(_cycler);
+  cdata->_vertices.push_back(short_vertex);
+
+  if (cdata->_got_minmax) {
+    cdata->_min_vertex = min(cdata->_min_vertex, short_vertex);
+    cdata->_max_vertex = max(cdata->_min_vertex, short_vertex);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::add_consecutive_vertices
+//       Access: Published
+//  Description: Adds a consecutive sequence of vertices, beginning at
+//               start, to the primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+add_consecutive_vertices(int start, int num_vertices) {
+  int end = (start + num_vertices) - 1;
+  unsigned short short_start = start;
+  unsigned short short_end = end;
+  nassertv((int)short_start == start && (int)short_end == end);
+
+  CDWriter cdata(_cycler);
+  for (unsigned short v = short_start; v <= short_end; ++v) {
+    cdata->_vertices.push_back(v);
+  }
+
+  if (cdata->_got_minmax) {
+    cdata->_min_vertex = min(cdata->_min_vertex, short_start);
+    cdata->_max_vertex = max(cdata->_min_vertex, short_end);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::close_primitive
+//       Access: Published
+//  Description: Indicates that the previous n calls to add_vertex(),
+//               since the last call to close_primitive(), have fully
+//               defined a new primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+close_primitive() {
+  int num_vertices_per_primitive = get_num_vertices_per_primitive();
+
+  CDWriter cdata(_cycler);
+  if (num_vertices_per_primitive == 0) {
+    // This is a complex primitive type like a triangle strip: each
+    // primitive uses a different number of vertices.
+    if (cdata->_lengths.empty() || 
+        cdata->_lengths.back() != (int)cdata->_vertices.size()) {
+      cdata->_lengths.push_back((int)cdata->_vertices.size());
+    }
+
+  } else {
+    // This is a simple primitive type like a triangle: each primitive
+    // uses the same number of vertices.  Assert that we added the
+    // correct number of vertices.
+    nassertv((int)cdata->_vertices.size() % num_vertices_per_primitive == 0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::clear_vertices
+//       Access: Published
+//  Description: Removes all of the vertices and primitives from the
+//               object, so they can be re-added.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+clear_vertices() {
+  CDWriter cdata(_cycler);
+  cdata->_vertices.clear();
+  cdata->_lengths.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::modify_vertices
+//       Access: Published
+//  Description: Returns a modifiable pointer to the vertex index
+//               list, so application code can directly fiddle with
+//               this data.  Use with caution, since there are no
+//               checks that the data will be left in a stable state.
+////////////////////////////////////////////////////////////////////
+PTA_ushort qpGeomPrimitive::
+modify_vertices() {
+  CDWriter cdata(_cycler);
+  return cdata->_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::set_vertices
+//       Access: Published
+//  Description: Completely replaces the vertex index list with a new
+//               table.  Chances are good that you should also replace
+//               the lengths list with set_lengths() at the same time.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+set_vertices(PTA_ushort vertices) {
+  CDWriter cdata(_cycler);
+  cdata->_vertices = vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::modify_lengths
+//       Access: Published
+//  Description: Returns a modifiable pointer to the primitive lengths
+//               array, so application code can directly fiddle with
+//               this data.  Use with caution, since there are no
+//               checks that the data will be left in a stable state.
+//
+//               Note that simple primitive types, like triangles, do
+//               not have a lengths array: since all the primitives
+//               have the same number of vertices, it is not needed.
+////////////////////////////////////////////////////////////////////
+PTA_int qpGeomPrimitive::
+modify_lengths() {
+  CDWriter cdata(_cycler);
+  return cdata->_lengths;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::set_lengths
+//       Access: Published
+//  Description: Completely replaces the primitive lengths array with
+//               a new table.  Chances are good that you should also
+//               replace the vertices list with set_vertices() at the
+//               same time.
+//
+//               Note that simple primitive types, like triangles, do
+//               not have a lengths array: since all the primitives
+//               have the same number of vertices, it is not needed.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+set_lengths(PTA_int lengths) {
+  CDWriter cdata(_cycler);
+  cdata->_lengths = lengths;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_num_vertices_per_primitive
+//       Access: Published, Virtual
+//  Description: If the primitive type is a simple type in which all
+//               primitives have the same number of vertices, like
+//               triangles, returns the number of vertices per
+//               primitive.  If the primitive type is a more complex
+//               type in which different primitives might have
+//               different numbers of vertices, for instance a
+//               triangle strip, returns 0.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_num_vertices_per_primitive() const {
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_num_primitives
+//       Access: Published
+//  Description: Returns the number of individual primitives stored
+//               within this object.  All primitives are the same
+//               type.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_num_primitives() const {
+  int num_vertices_per_primitive = get_num_vertices_per_primitive();
+
+  CDReader cdata(_cycler);
+  if (num_vertices_per_primitive == 0) {
+    // This is a complex primitive type like a triangle strip: each
+    // primitive uses a different number of vertices.
+    return cdata->_lengths.size();
+
+  } else {
+    // This is a simple primitive type like a triangle: each primitive
+    // uses the same number of vertices.
+    return ((int)cdata->_vertices.size() / num_vertices_per_primitive);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_primitive_start
+//       Access: Published
+//  Description: Returns the element within the _vertices list at which
+//               the ith primitive starts.  
+//
+//               If i is one more than the highest valid primitive
+//               vertex, the return value will be one more than the
+//               last valid vertex.  Thus, it is always true that the
+//               vertices used by a particular primitive i are the set
+//               get_primitive_start(i) <= vi < get_primitive_start(i
+//               + 1).
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_primitive_start(int i) const {
+  int num_vertices_per_primitive = get_num_vertices_per_primitive();
+
+  if (num_vertices_per_primitive == 0) {
+    // This is a complex primitive type like a triangle strip: each
+    // primitive uses a different number of vertices.
+    CDReader cdata(_cycler);
+    nassertr(i >= 0 && i <= (int)cdata->_lengths.size(), -1);
+    if (i == 0) {
+      return 0;
+    } else {
+      return cdata->_lengths[i - 1];
+    }
+
+  } else {
+    // This is a simple primitive type like a triangle: each primitive
+    // uses the same number of vertices.
+    return i * num_vertices_per_primitive;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::get_primitive_num_vertices
+//       Access: Published
+//  Description: Returns the number of vertices used by the ith
+//               primitive.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::
+get_primitive_num_vertices(int i) const {
+  int num_vertices_per_primitive = get_num_vertices_per_primitive();
+
+  if (num_vertices_per_primitive == 0) {
+    // This is a complex primitive type like a triangle strip: each
+    // primitive uses a different number of vertices.
+    CDReader cdata(_cycler);
+    nassertr(i >= 0 && i < (int)cdata->_lengths.size(), 0);
+    return cdata->_lengths[i];
+
+  } else {
+    // This is a simple primitive type like a triangle: each primitive
+    // uses the same number of vertices.
+    return num_vertices_per_primitive;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::decompose
+//       Access: Published, Virtual
+//  Description: Decomposes a complex primitive type into a simpler
+//               primitive type, for instance triangle strips to
+//               triangles, and returns a pointer to the new primitive
+//               definition.  If the decomposition cannot be
+//               performed, this might return the original object.
+//
+//               This method is useful for application code that wants
+//               to iterate through the set of triangles on the
+//               primitive without having to write handlers for each
+//               possible kind of primitive type.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomPrimitive::
+decompose(const qpGeomVertexData *vertex_data) {
+  return this;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::output
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+output(ostream &out, const qpGeomVertexData *vertex_data) const {
+  out << get_type() << ", " << get_num_primitives()
+      << ", " << get_num_vertices();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::write
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+write(ostream &out, const qpGeomVertexData *vertex_data,
+      int indent_level) const {
+  indent(out, indent_level)
+    << get_type() << ":\n";
+  int num_primitives = get_num_primitives();
+  for (int i = 0; i < num_primitives; i++) {
+    indent(out, indent_level + 2)
+      << "[";
+    int begin = get_primitive_start(i);
+    int end = get_primitive_start(i + 1);
+    for (int vi = begin; vi < end; vi++) {
+      out << " " << get_vertex(vi);
+    }
+    out << " ]\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::calc_tight_bounds
+//       Access: Public, Virtual
+//  Description: Expands min_point and max_point to include all of the
+//               vertices in the Geom, if any.  found_any is set true
+//               if any points are found.  It is the caller's
+//               responsibility to initialize min_point, max_point,
+//               and found_any before calling this function.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
+                  bool &found_any, 
+                  const qpGeomVertexData *vertex_data) const {
+  CDReader cdata(_cycler);
+
+  const qpGeomVertexFormat *format = vertex_data->get_format();
+
+  int array_index = format->get_array_with(InternalName::get_vertex());
+  if (array_index < 0) {
+    // No vertex data.
+    return;
+  }
+
+  const qpGeomVertexArrayFormat *array_format = format->get_array(array_index);
+  const qpGeomVertexDataType *data_type = 
+    array_format->get_data_type(InternalName::get_vertex());
+
+  int stride = array_format->get_stride();
+  int start = data_type->get_start();
+  int num_components = data_type->get_num_components();
+
+  CPTA_uchar array_data = vertex_data->get_array_data(array_index);
+
+  PTA_ushort::const_iterator ii;
+  for (ii = cdata->_vertices.begin(); ii != cdata->_vertices.end(); ++ii) {
+    int index = (int)(*ii);
+    const PN_float32 *v = (const PN_float32 *)&array_data[start + index * stride];
+
+    LPoint3f vertex;
+    qpGeomVertexData::to_vec3(vertex, v, num_components);
+
+    if (found_any) {
+      min_point.set(min(min_point[0], vertex[0]),
+                    min(min_point[1], vertex[1]),
+                    min(min_point[2], vertex[2]));
+      max_point.set(max(max_point[0], vertex[0]),
+                    max(max_point[1], vertex[1]),
+                    max(max_point[2], vertex[2]));
+    } else {
+      min_point = vertex;
+      max_point = vertex;
+      found_any = true;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::recompute_minmax
+//       Access: Private
+//  Description: Recomputes the _min_vertex and _max_vertex values if
+//               necessary.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+recompute_minmax() {
+  CDWriter cdata(_cycler);
+  
+  if (cdata->_vertices.empty()) {
+    cdata->_min_vertex = 0;
+    cdata->_max_vertex = 0;
+  } else {
+    PTA_ushort::const_iterator ii = cdata->_vertices.begin();
+    cdata->_min_vertex = (*ii);
+    cdata->_max_vertex = (*ii);
+    
+    ++ii;
+    while (ii != cdata->_vertices.end()) {
+      cdata->_min_vertex = min(cdata->_min_vertex, (*ii));
+      cdata->_max_vertex = max(cdata->_min_vertex, (*ii));
+      
+      ++ii;
+    }
+  }
+
+  cdata->_got_minmax = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  TypedWritable::write_datagram(manager, dg);
+
+  manager->write_cdata(dg, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeomPrimitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  TypedWritable::fillin(scan, manager);
+
+  manager->read_cdata(scan, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::make_copy
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData *qpGeomPrimitive::CData::
+make_copy() const {
+  return new CData(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::CData::
+write_datagram(BamWriter *manager, Datagram &dg) const {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int qpGeomPrimitive::CData::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = CycleData::complete_pointers(p_list, manager);
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::CData::fillin
+//       Access: Public, Virtual
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeomPrimitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::CData::
+fillin(DatagramIterator &scan, BamReader *manager) {
+}

+ 156 - 0
panda/src/gobj/qpgeomPrimitive.h

@@ -0,0 +1,156 @@
+// Filename: qpgeomPrimitive.h
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMPRIMITIVE_H
+#define qpGEOMPRIMITIVE_H
+
+#include "pandabase.h"
+#include "typedWritableReferenceCount.h"
+#include "luse.h"
+#include "pointerTo.h"
+#include "pta_ushort.h"
+#include "pta_int.h"
+#include "cycleData.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "pipelineCycler.h"
+
+class qpGeomVertexData;
+class GraphicsStateGuardianBase;
+class GeomContext;
+class FactoryParams;
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomPrimitive
+// Description : This is an abstract base class for a family of
+//               classes that represent the fundamental geometry
+//               primitives that may be stored in a Geom.
+//
+//               They all have in common the fact that they are
+//               defined by tables of vertex data stored in a
+//               GeomVertexData object.  Each GeomPrimitive object
+//               contains an ordered list of integers, which index
+//               into the vertex array defined by the GeomVertexData
+//               and define the particular vertices of the
+//               GeomVertexData that are used for this primitive.
+//
+//               The meaning of a given arrangement of vertices is
+//               defined by each individual primitive type; for
+//               instance, a GeomTriangle renders a triangle from each
+//               three consecutive vertices, while a GeomTriangleStrip
+//               renders a strip of (n - 2) connected triangles from
+//               each sequence of n vertices.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomPrimitive : public TypedWritableReferenceCount {
+PUBLISHED:
+  qpGeomPrimitive();
+  qpGeomPrimitive(const qpGeomPrimitive &copy);
+  virtual ~qpGeomPrimitive();
+
+  INLINE int get_num_vertices() const;
+  INLINE int get_vertex(int i) const;
+  void add_vertex(int vertex);
+  void add_consecutive_vertices(int start, int num_vertices);
+  void close_primitive();
+  void clear_vertices();
+
+  INLINE CPTA_ushort get_vertices() const;
+  PTA_ushort modify_vertices();
+  void set_vertices(PTA_ushort vertices);
+
+  INLINE CPTA_int get_lengths() const;
+  PTA_int modify_lengths();
+  void set_lengths(PTA_int lengths);
+
+  INLINE int get_min_vertex() const;
+  INLINE int get_max_vertex() const;
+
+  virtual int get_num_vertices_per_primitive() const;
+  int get_num_primitives() const;
+  int get_primitive_start(int i) const;
+  int get_primitive_num_vertices(int i) const;
+
+  virtual PT(qpGeomPrimitive) decompose(const qpGeomVertexData *vertex_data);
+
+  virtual void output(ostream &out, const qpGeomVertexData *vertex_data) const;
+  virtual void write(ostream &out, const qpGeomVertexData *vertex_data, 
+                     int indent_level) const;
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg)=0;
+
+  virtual void calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
+                                 bool &found_any, 
+                                 const qpGeomVertexData *vertex_data) const;
+
+private:
+  // This is the data that must be cycled between pipeline stages.
+  class EXPCL_PANDA CData : public CycleData {
+  public:
+    INLINE CData();
+    INLINE CData(const CData &copy);
+    virtual CycleData *make_copy() const;
+    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
+    virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
+    virtual void fillin(DatagramIterator &scan, BamReader *manager);
+
+    PTA_ushort _vertices;
+    PTA_int _lengths;
+
+    bool _got_minmax;
+    unsigned short _min_vertex;
+    unsigned short _max_vertex;
+  };
+
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
+
+  void recompute_minmax();
+
+public:
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "qpGeomPrimitive",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class qpGeom;
+};
+
+#include "qpgeomPrimitive.I"
+
+#endif

+ 110 - 0
panda/src/gobj/qpgeomTriangles.cxx

@@ -0,0 +1,110 @@
+// Filename: qpgeomTriangles.cxx
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomTriangles.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomTriangles::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTriangles::
+qpGeomTriangles() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTriangles::
+qpGeomTriangles(const qpGeomTriangles &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTriangles::
+~qpGeomTriangles() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::get_num_vertices_per_primitive
+//       Access: Published, Virtual
+//  Description: If the primitive type is a simple type in which all
+//               primitives have the same number of vertices, like
+//               triangles, returns the number of vertices per
+//               primitive.  If the primitive type is a more complex
+//               type in which different primitives might have
+//               different numbers of vertices, for instance a
+//               triangle strip, returns 0.
+////////////////////////////////////////////////////////////////////
+int qpGeomTriangles::
+get_num_vertices_per_primitive() const {
+  return 3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomTriangles::
+draw(GraphicsStateGuardianBase *gsg) {
+  gsg->draw_triangles(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomTriangles::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTriangles::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomTriangles::
+make_from_bam(const FactoryParams &params) {
+  qpGeomTriangles *object = new qpGeomTriangles;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 68 - 0
panda/src/gobj/qpgeomTriangles.h

@@ -0,0 +1,68 @@
+// Filename: qpgeomTriangles.h
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMTRIANGLES_H
+#define qpGEOMTRIANGLES_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomTriangles
+// Description : Defines a series of disconnected triangles.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomTriangles : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomTriangles();
+  qpGeomTriangles(const qpGeomTriangles &copy);
+  virtual ~qpGeomTriangles();
+
+  virtual int get_num_vertices_per_primitive() const;
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg);
+
+public:
+  static void register_with_read_factory();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomPrimitive::init_type();
+    register_type(_type_handle, "qpGeomTriangles",
+                  qpGeomPrimitive::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class qpGeom;
+};
+
+#endif

+ 138 - 0
panda/src/gobj/qpgeomTrifans.cxx

@@ -0,0 +1,138 @@
+// Filename: qpgeomTrifans.cxx
+// Created by:  drose (08Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomTrifans.h"
+#include "qpgeomTriangles.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomTrifans::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTrifans::
+qpGeomTrifans() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTrifans::
+qpGeomTrifans(const qpGeomTrifans &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTrifans::
+~qpGeomTrifans() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::decompose
+//       Access: Published, Virtual
+//  Description: Decomposes a complex primitive type into a simpler
+//               primitive type, for instance triangle strips to
+//               triangles, and returns a pointer to the new primitive
+//               definition.  If the decomposition cannot be
+//               performed, this might return the original object.
+//
+//               This method is useful for application code that wants
+//               to iterate through the set of triangles on the
+//               primitive without having to write handlers for each
+//               possible kind of primitive type.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomTrifans::
+decompose(const qpGeomVertexData *) {
+  PT(qpGeomTriangles) triangles = new qpGeomTriangles;
+  CPTA_ushort vertices = get_vertices();
+  CPTA_int lengths = get_lengths();
+
+  CPTA_ushort::const_iterator vi;
+  vi = vertices.begin();
+
+  CPTA_int::const_iterator li;
+  for (li = lengths.begin(); li != lengths.end(); ++li) {
+    int length = (*li);
+    nassertr(length >= 2, triangles.p());
+    int v0 = (*vi);
+    ++vi;
+    int v1 = (*vi);
+    ++vi;
+    for (int i = 2; i < length; i++) {
+      triangles->add_vertex(v0);
+      triangles->add_vertex(v1);
+      triangles->add_vertex(*vi);
+      triangles->close_primitive();
+      ++vi;
+    }
+  }
+
+  return triangles.p();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomTrifans::
+draw(GraphicsStateGuardianBase *gsg) {
+  gsg->draw_trifans(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomTrifans::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTrifans::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomTrifans::
+make_from_bam(const FactoryParams &params) {
+  qpGeomTrifans *object = new qpGeomTrifans;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 68 - 0
panda/src/gobj/qpgeomTrifans.h

@@ -0,0 +1,68 @@
+// Filename: qpgeomTrifans.h
+// Created by:  drose (08Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMTRIFANS_H
+#define qpGEOMTRIFANS_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomTrifans
+// Description : Defines a series of triangle fans.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomTrifans : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomTrifans();
+  qpGeomTrifans(const qpGeomTrifans &copy);
+  virtual ~qpGeomTrifans();
+
+  virtual PT(qpGeomPrimitive) decompose(const qpGeomVertexData *vertex_data);
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg);
+
+public:
+  static void register_with_read_factory();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomPrimitive::init_type();
+    register_type(_type_handle, "qpGeomTrifans",
+                  qpGeomPrimitive::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class qpGeom;
+};
+
+#endif

+ 148 - 0
panda/src/gobj/qpgeomTristrips.cxx

@@ -0,0 +1,148 @@
+// Filename: qpgeomTristrips.cxx
+// Created by:  drose (08Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomTristrips.h"
+#include "qpgeomTriangles.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+TypeHandle qpGeomTristrips::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTristrips::
+qpGeomTristrips() {
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTristrips::
+qpGeomTristrips(const qpGeomTristrips &copy) :
+  qpGeomPrimitive(copy)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTristrips::
+~qpGeomTristrips() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::decompose
+//       Access: Published, Virtual
+//  Description: Decomposes a complex primitive type into a simpler
+//               primitive type, for instance triangle strips to
+//               triangles, and returns a pointer to the new primitive
+//               definition.  If the decomposition cannot be
+//               performed, this might return the original object.
+//
+//               This method is useful for application code that wants
+//               to iterate through the set of triangles on the
+//               primitive without having to write handlers for each
+//               possible kind of primitive type.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomPrimitive) qpGeomTristrips::
+decompose(const qpGeomVertexData *) {
+  PT(qpGeomTriangles) triangles = new qpGeomTriangles;
+  CPTA_ushort vertices = get_vertices();
+  CPTA_int lengths = get_lengths();
+
+  CPTA_ushort::const_iterator vi;
+  vi = vertices.begin();
+
+  CPTA_int::const_iterator li;
+  for (li = lengths.begin(); li != lengths.end(); ++li) {
+    int length = (*li);
+    nassertr(length >= 2, triangles.p());
+    int v0 = (*vi);
+    ++vi;
+    int v1 = (*vi);
+    ++vi;
+    bool reversed = false;
+    for (int i = 2; i < length; i++) {
+      if (reversed) {
+        triangles->add_vertex(v1);
+        triangles->add_vertex(v0);
+        reversed = false;
+      } else {
+        triangles->add_vertex(v0);
+        triangles->add_vertex(v1);
+        reversed = true;
+      }
+      triangles->add_vertex(*vi);
+      v0 = v1;
+      v1 = *vi;
+      triangles->close_primitive();
+      ++vi;
+    }
+  }
+
+  return triangles.p();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::draw
+//       Access: Public, Virtual
+//  Description: Calls the appropriate method on the GSG to draw the
+//               primitive.
+////////////////////////////////////////////////////////////////////
+void qpGeomTristrips::
+draw(GraphicsStateGuardianBase *gsg) {
+  gsg->draw_tristrips(this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeom.
+////////////////////////////////////////////////////////////////////
+void qpGeomTristrips::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTristrips::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeom is encountered
+//               in the Bam file.  It should create the qpGeom
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomTristrips::
+make_from_bam(const FactoryParams &params) {
+  qpGeomTristrips *object = new qpGeomTristrips;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}

+ 68 - 0
panda/src/gobj/qpgeomTristrips.h

@@ -0,0 +1,68 @@
+// Filename: qpgeomTristrips.h
+// Created by:  drose (08Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMTRISTRIPS_H
+#define qpGEOMTRISTRIPS_H
+
+#include "pandabase.h"
+#include "qpgeomPrimitive.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomTristrips
+// Description : Defines a series of triangle strips.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomTristrips : public qpGeomPrimitive {
+PUBLISHED:
+  qpGeomTristrips();
+  qpGeomTristrips(const qpGeomTristrips &copy);
+  virtual ~qpGeomTristrips();
+
+  virtual PT(qpGeomPrimitive) decompose(const qpGeomVertexData *vertex_data);
+
+public:
+  virtual void draw(GraphicsStateGuardianBase *gsg);
+
+public:
+  static void register_with_read_factory();
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    qpGeomPrimitive::init_type();
+    register_type(_type_handle, "qpGeomTristrips",
+                  qpGeomPrimitive::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class qpGeom;
+};
+
+#endif

+ 121 - 0
panda/src/gobj/qpgeomVertexArrayFormat.I

@@ -0,0 +1,121 @@
+// Filename: qpgeomVertexArrayFormat.I
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomVertexArrayFormat::is_registered
+//       Access: Published
+//  Description: Returns true if this format has been registered,
+//               false if it has not.  It may not be used for a Geom
+//               until it has been registered, but once registered, it
+//               may no longer be modified.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomVertexArrayFormat::
+is_registered() const {
+  return _is_registered;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_stride
+//       Access: Published
+//  Description: Returns the total number of bytes reserved in the
+//               array for each vertex.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexArrayFormat::
+get_stride() const {
+  return _stride;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::set_stride
+//       Access: Published
+//  Description: Changes the total number of bytes reserved in the
+//               array for each vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexArrayFormat::
+set_stride(int stride) {
+  nassertv(!_is_registered);
+  _stride = stride;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_total_bytes
+//       Access: Published
+//  Description: Returns the total number of bytes used by the data
+//               types within the format, including gaps between
+//               elements.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexArrayFormat::
+get_total_bytes() const {
+  return _total_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_pad_to
+//       Access: Published
+//  Description: Returns the byte divisor to which the data record
+//               must be padded to meet hardware limitations.  For
+//               instance, if this is 4, the stride will be
+//               automatically rounded up to the next multiple of 4
+//               bytes.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexArrayFormat::
+get_pad_to() const {
+  return _pad_to;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_num_data_types
+//       Access: Published
+//  Description: Returns the number of different data types in the
+//               specification.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexArrayFormat::
+get_num_data_types() const {
+  return (int)_data_types.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_data_type
+//       Access: Published
+//  Description: Returns the ith data types of the specification.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexDataType *qpGeomVertexArrayFormat::
+get_data_type(int i) const {
+  nassertr(i >= 0 && i < (int)_data_types.size(), NULL);
+  consider_sort_data_types();
+  return _data_types[i];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::consider_sort_data_types
+//       Access: Private
+//  Description: Resorts the _data_types vector if necessary.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexArrayFormat::
+consider_sort_data_types() const {
+  if (_data_types_unsorted) {
+    ((qpGeomVertexArrayFormat *)this)->sort_data_types();
+  }
+}
+
+INLINE ostream &
+operator << (ostream &out, const qpGeomVertexArrayFormat &obj) {
+  obj.output(out);
+  return out;
+}

+ 556 - 0
panda/src/gobj/qpgeomVertexArrayFormat.cxx

@@ -0,0 +1,556 @@
+// Filename: qpgeomVertexArrayFormat.cxx
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomVertexFormat.h"
+#include "qpgeomVertexDataType.h"
+#include "qpgeomVertexData.h"
+#include "indent.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "indirectLess.h"
+
+TypeHandle qpGeomVertexArrayFormat::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+qpGeomVertexArrayFormat() :
+  _is_registered(false),
+  _stride(0),
+  _total_bytes(0),
+  _pad_to(1),
+  _data_types_unsorted(false)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                        qpGeomVertexDataType::NumericType numeric_type0) :
+  _is_registered(false),
+  _stride(0),
+  _total_bytes(0),
+  _pad_to(1),
+  _data_types_unsorted(false)
+{
+  add_data_type(name0, num_components0, numeric_type0);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                        qpGeomVertexDataType::NumericType numeric_type0,
+                        const InternalName *name1, int num_components1,
+                        qpGeomVertexDataType::NumericType numeric_type1) :
+  _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);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                        qpGeomVertexDataType::NumericType numeric_type0,
+                        const InternalName *name1, int num_components1,
+                        qpGeomVertexDataType::NumericType numeric_type1,
+                        const InternalName *name2, int num_components2,
+                        qpGeomVertexDataType::NumericType numeric_type2) :
+  _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);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                        qpGeomVertexDataType::NumericType numeric_type0,
+                        const InternalName *name1, int num_components1,
+                        qpGeomVertexDataType::NumericType numeric_type1,
+                        const InternalName *name2, int num_components2,
+                        qpGeomVertexDataType::NumericType numeric_type2,
+                        const InternalName *name3, int num_components3,
+                        qpGeomVertexDataType::NumericType numeric_type3) :
+  _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);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+qpGeomVertexArrayFormat(const qpGeomVertexArrayFormat &copy) :
+  _is_registered(false),
+  _stride(copy._stride),
+  _total_bytes(copy._total_bytes),
+  _pad_to(copy._pad_to),
+  _data_types_unsorted(copy._data_types_unsorted)
+{
+  DataTypes::const_iterator dti;
+  for (dti = copy._data_types.begin(); dti != copy._data_types.end(); ++dti) {
+    add_data_type(*(*dti));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Copy Assignment Operator
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+operator = (const qpGeomVertexArrayFormat &copy) {
+  nassertv(!_is_registered);
+  _stride = copy._stride;
+  _total_bytes = copy._total_bytes;
+  _pad_to = copy._pad_to;
+
+  _data_types.clear();
+  _data_types_by_name.clear();
+  _data_types_unsorted = false;
+  DataTypes::const_iterator dti;
+  for (dti = copy._data_types.begin(); dti != copy._data_types.end(); ++dti) {
+    add_data_type(*(*dti));
+  }
+}
+  
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat::
+~qpGeomVertexArrayFormat() {
+  // Once registered, these things should not be deallocated.
+  nassertv(!_is_registered);
+
+  DataTypes::iterator dti;
+  for (dti = _data_types.begin(); dti != _data_types.end(); ++dti) {
+    delete (*dti);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::add_data_type
+//       Access: Published
+//  Description: Adds a new data type to the specification.  This is a
+//               table of per-vertex floating-point numbers such as
+//               "vertex" or "normal"; you must specify where in each
+//               record the table starts, and how many components
+//               (dimensions) exist per vertex.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+add_data_type(const InternalName *name, int num_components, 
+              qpGeomVertexDataType::NumericType numeric_type, int start) {
+  if (start < 0) {
+    start = _total_bytes;
+
+    qpGeomVertexDataType temp_data_type(name, num_components, numeric_type, 0);
+    int pad_to = temp_data_type.get_component_bytes();
+    start = ((start + pad_to - 1) / pad_to) * pad_to;
+  }
+
+  add_data_type(qpGeomVertexDataType(name, num_components, 
+                                     numeric_type, start));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::add_data_type
+//       Access: Published
+//  Description: Adds a new data type to the specification.  This is a
+//               table of per-vertex floating-point numbers such as
+//               "vertex" or "normal"; you must specify where in each
+//               record the table starts, and how many components
+//               (dimensions) exist per vertex.
+//
+//               Adding a data type with the same name as a previous
+//               type, or that overlaps with one or more previous
+//               types, quietly removes the previous type(s).
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+add_data_type(const qpGeomVertexDataType &data_type) {
+  nassertv(!_is_registered);
+
+  // Make sure there isn't already a data type with this name.
+  remove_data_type(data_type.get_name());
+
+  // Also make sure there aren't any data types that overlap with this
+  // one.
+  const qpGeomVertexDataType *orig_data_type = get_data_type(data_type.get_start(), data_type.get_total_bytes());
+  while (orig_data_type != (const qpGeomVertexDataType *)NULL) {
+    remove_data_type(orig_data_type->get_name());
+    orig_data_type = get_data_type(data_type.get_start(), data_type.get_total_bytes());
+  }
+
+  _total_bytes = max(_total_bytes, data_type.get_start() + data_type.get_total_bytes());
+  _pad_to = max(_pad_to, data_type.get_component_bytes());
+  _stride = max(_stride, ((_total_bytes + _pad_to - 1) / _pad_to) * _pad_to);
+
+  qpGeomVertexDataType *new_data_type = new qpGeomVertexDataType(data_type);
+
+  if (!_data_types.empty() && *new_data_type < *_data_types.back()) {
+    _data_types_unsorted = true;
+  }
+
+  _data_types.push_back(new_data_type);
+  _data_types_by_name.insert(DataTypesByName::value_type(new_data_type->get_name(), new_data_type));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::remove_data_type
+//       Access: Published
+//  Description: Removes the data type with the indicated name, if
+//               any.  This leaves a gap in the byte structure.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+remove_data_type(const InternalName *name) {
+  nassertv(!_is_registered);
+  DataTypesByName::iterator ni;
+  ni = _data_types_by_name.find(name);
+  if (ni != _data_types_by_name.end()) {
+    qpGeomVertexDataType *data_type = (*ni).second;
+    _data_types_by_name.erase(ni);
+
+    DataTypes::iterator dti;
+    dti = find(_data_types.begin(), _data_types.end(), data_type);
+    nassertv(dti != _data_types.end());
+    _data_types.erase(dti);
+
+    delete data_type;
+
+    // Maybe we just removed the tail data_type.  If that's so, we
+    // should recompute _total_bytes to reflect the new tail.
+    if (_data_types.empty()) {
+      _total_bytes = 0;
+    } else {
+      consider_sort_data_types();
+      qpGeomVertexDataType *last = _data_types.back();
+      _total_bytes = last->get_start() + last->get_total_bytes();
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::clear_data_types
+//       Access: Published
+//  Description: Removes all data types previously added, sets the
+//               stride to zero, and prepares to start over.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+clear_data_types() {
+  _data_types.clear();
+  _data_types_by_name.clear();
+  _data_types_unsorted = false;
+  _stride = 0;
+  _total_bytes = 0;
+  _pad_to = 1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_data_type
+//       Access: Published
+//  Description: Returns the specification with the indicated name, or
+//               NULL if the name is not used.
+////////////////////////////////////////////////////////////////////
+const qpGeomVertexDataType *qpGeomVertexArrayFormat::
+get_data_type(const InternalName *name) const {
+  DataTypesByName::const_iterator ni;
+  ni = _data_types_by_name.find(name);
+  if (ni != _data_types_by_name.end()) {
+    return (*ni).second;
+  }
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::get_data_type
+//       Access: Published
+//  Description: Returns the first specification that overlaps with
+//               any of the indicated bytes in the range, or NULL if
+//               none do.
+////////////////////////////////////////////////////////////////////
+const qpGeomVertexDataType *qpGeomVertexArrayFormat::
+get_data_type(int start_byte, int num_bytes) const {
+  consider_sort_data_types();
+  DataTypes::const_iterator dti;
+  for (dti = _data_types.begin(); dti != _data_types.end(); ++dti) {
+    const qpGeomVertexDataType *data_type = (*dti);
+    if (data_type->overlaps_with(start_byte, num_bytes)) {
+      return data_type;
+    }
+  }
+
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::is_data_subset_of
+//       Access: Published
+//  Description: Returns true if all of the fields in this array
+//               format are also present and equivalent in the other
+//               array format, and in the same byte positions, and the
+//               stride is the same.  That is, true if this format can
+//               share the same data pointer as the other format (with
+//               possibly some unused gaps).
+////////////////////////////////////////////////////////////////////
+bool qpGeomVertexArrayFormat::
+is_data_subset_of(const qpGeomVertexArrayFormat &other) const {
+  if (_data_types.size() > other._data_types.size() ||
+      get_stride() != other.get_stride()) {
+    return false;
+  }
+
+  consider_sort_data_types();
+  other.consider_sort_data_types();
+  size_t i = 0;
+  size_t j = 0;
+  while (i < _data_types.size() && j < other._data_types.size()) {
+    if (*_data_types[i] == *other._data_types[j]) {
+      ++i;
+    }
+    ++j;
+  }
+
+  // If we reached the end of our list, all fields matched.
+  return (i == _data_types.size());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+output(ostream &out) const {
+  DataTypes::const_iterator dti;
+  out << "[";
+  for (dti = _data_types.begin(); dti != _data_types.end(); ++dti) {
+    const qpGeomVertexDataType *data_type = (*dti);
+    out << " " << *data_type;
+  }
+  out << " ]";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::write
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+write(ostream &out, int indent_level) const {
+  indent(out, indent_level)
+    << "Array format (stride = " << get_stride() << "):\n";
+  consider_sort_data_types();
+  DataTypes::const_iterator dti;
+  for (dti = _data_types.begin(); dti != _data_types.end(); ++dti) {
+    const qpGeomVertexDataType *data_type = (*dti);
+    indent(out, indent_level + 2)
+      << *data_type << " start at " << data_type->get_start() << "\n";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::write_with_data
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+write_with_data(ostream &out, int indent_level,
+                const qpGeomVertexData *data, int array_index) const {
+  consider_sort_data_types();
+  int num_vertices = data->get_num_vertices();
+  for (int i = 0; i < num_vertices; i++) {
+    indent(out, indent_level)
+      << "vertex index " << i << ":\n";
+    DataTypes::const_iterator dti;
+    for (dti = _data_types.begin(); dti != _data_types.end(); ++dti) {
+      const qpGeomVertexDataType *data_type = (*dti);
+      int num_values = min(data_type->get_num_values(), 4);
+      float data_values[4]; 
+      data->get_data(array_index, data_type, i, data_values, num_values);
+
+      indent(out, indent_level + 2) 
+        << *data_type->get_name();
+      for (int v = 0; v < num_values; v++) {
+        out << " " << data_values[v];
+      }
+      out << "\n";
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::compare_to
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexArrayFormat::
+compare_to(const qpGeomVertexArrayFormat &other) const {
+  if (_stride != other._stride) {
+    return _stride - other._stride;
+  }
+  if (_total_bytes != other._total_bytes) {
+    return _total_bytes - other._total_bytes;
+  }
+  if (_pad_to != other._pad_to) {
+    return _pad_to - other._pad_to;
+  }
+  if (_data_types.size() != other._data_types.size()) {
+    return (int)_data_types.size() - (int)other._data_types.size();
+  }
+  consider_sort_data_types();
+  other.consider_sort_data_types();
+  for (size_t i = 0; i < _data_types.size(); i++) {
+    int compare = _data_types[i]->compare_to(*other._data_types[i]);
+    if (compare != 0) {
+      return compare;
+    }
+  }
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::sort_data_types
+//       Access: Private
+//  Description: Resorts the _data_types vector so that the data types
+//               are listed in the same order they appear in the
+//               record.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+sort_data_types() {
+  sort(_data_types.begin(), _data_types.end(), IndirectLess<qpGeomVertexDataType>());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::do_register
+//       Access: Private
+//  Description: Called internally when the format is registered.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+do_register() {
+  nassertv(!_is_registered);
+  _is_registered = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeomVertexArrayFormat.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  TypedWritableReferenceCount::write_datagram(manager, dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexArrayFormat::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeomVertexArrayFormat is
+//               encountered in the Bam file.  It should create the
+//               qpGeomVertexArrayFormat and extract its information from
+//               the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomVertexArrayFormat::
+make_from_bam(const FactoryParams &params) {
+  qpGeomVertexArrayFormat *object = new qpGeomVertexArrayFormat;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayFormat::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeomVertexArrayFormat.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayFormat::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  TypedWritableReferenceCount::fillin(scan, manager);
+}

+ 162 - 0
panda/src/gobj/qpgeomVertexArrayFormat.h

@@ -0,0 +1,162 @@
+// Filename: qpgeomVertexArrayFormat.h
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMVERTEXARRAYFORMAT_H
+#define qpGEOMVERTEXARRAYFORMAT_H
+
+#include "pandabase.h"
+#include "typedWritableReferenceCount.h"
+#include "qpgeomVertexDataType.h"
+#include "pvector.h"
+#include "pmap.h"
+
+class qpGeomVertexFormat;
+class qpGeomVertexData;
+class InternalName;
+class FactoryParams;
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomVertexArrayFormat
+// Description : This describes the structure of a single array within
+//               a Geom data.  See GeomVertexFormat for the parent
+//               class which collects together all of the individual
+//               GeomVertexArrayFormat objects.
+//
+//               A particular array may include any number of standard
+//               or user-defined data types.  All data types consist
+//               of a sequence of one or more floating-point numbers;
+//               the semantic meaning of the data type is implicit
+//               from its name.  The standard array types are named
+//               "vertex", "normal", "texcoord", "color", "tangent",
+//               and "binormal"; other data may be stored simply by
+//               choosing a different name.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomVertexArrayFormat : public TypedWritableReferenceCount {
+PUBLISHED:
+  qpGeomVertexArrayFormat();
+  qpGeomVertexArrayFormat(const qpGeomVertexArrayFormat &copy);
+  qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                          qpGeomVertexDataType::NumericType numeric_type0);
+  qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                          qpGeomVertexDataType::NumericType numeric_type0,
+                          const InternalName *name1, int num_components1,
+                          qpGeomVertexDataType::NumericType numeric_type1);
+  qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                          qpGeomVertexDataType::NumericType numeric_type0,
+                          const InternalName *name1, int num_components1,
+                          qpGeomVertexDataType::NumericType numeric_type1,
+                          const InternalName *name2, int num_components2,
+                          qpGeomVertexDataType::NumericType numeric_type2);
+  qpGeomVertexArrayFormat(const InternalName *name0, int num_components0,
+                          qpGeomVertexDataType::NumericType numeric_type0,
+                          const InternalName *name1, int num_components1,
+                          qpGeomVertexDataType::NumericType numeric_type1,
+                          const InternalName *name2, int num_components2,
+                          qpGeomVertexDataType::NumericType numeric_type2,
+                          const InternalName *name3, int num_components3,
+                          qpGeomVertexDataType::NumericType numeric_type3);
+  void operator = (const qpGeomVertexArrayFormat &copy);
+  ~qpGeomVertexArrayFormat();
+
+  INLINE bool is_registered() const;
+
+  INLINE int get_stride() const;
+  INLINE void set_stride(int stride);
+
+  INLINE int get_total_bytes() const;
+  INLINE int get_pad_to() const;
+
+  void add_data_type(const InternalName *name, int num_components,
+                     qpGeomVertexDataType::NumericType numeric_type,
+                     int start = -1);
+  void add_data_type(const qpGeomVertexDataType &data_type);
+  void remove_data_type(const InternalName *name);
+  void clear_data_types();
+
+  INLINE int get_num_data_types() const;
+  INLINE const qpGeomVertexDataType *get_data_type(int i) const;
+
+  const qpGeomVertexDataType *get_data_type(const InternalName *name) const;
+  const qpGeomVertexDataType *get_data_type(int start_byte, int num_bytes) const;
+
+  bool is_data_subset_of(const qpGeomVertexArrayFormat &other) const;
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level = 0) const;
+  void write_with_data(ostream &out, int indent_level, 
+                       const qpGeomVertexData *data, int array_index) const;
+
+public:
+  int compare_to(const qpGeomVertexArrayFormat &other) const;
+
+private:
+  INLINE void consider_sort_data_types() const;
+  void sort_data_types();
+  void do_register();
+
+  bool _is_registered;
+  const qpGeomVertexFormat *_root_format;
+  const qpGeomVertexFormat *_parent_format;
+
+  int _stride;
+  int _total_bytes;
+  int _pad_to;
+
+  typedef pvector<qpGeomVertexDataType *> DataTypes;
+  DataTypes _data_types;
+  bool _data_types_unsorted;
+
+  typedef pmap<const InternalName *, qpGeomVertexDataType *> DataTypesByName;
+  DataTypesByName _data_types_by_name;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "qpGeomVertexArrayFormat",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class qpGeomVertexFormat;
+};
+
+INLINE ostream &operator << (ostream &out, const qpGeomVertexArrayFormat &obj);
+
+#include "qpgeomVertexArrayFormat.I"
+
+#endif

+ 82 - 0
panda/src/gobj/qpgeomVertexData.I

@@ -0,0 +1,82 @@
+// Filename: qpgeomVertexData.I
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomVertexData::get_format
+//       Access: Published
+//  Description: Returns a pointer to the GeomVertexFormat structure
+//               that defines this data.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexData::
+get_format() const {
+  return _format;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::get_num_arrays
+//       Access: Published
+//  Description: Returns the number of individual arrays stored within
+//               the data.  This must match
+//               get_format()->get_num_arrays().
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexData::
+get_num_arrays() const {
+  CDReader cdata(_cycler);
+  return cdata->_arrays.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::get_array_data
+//       Access: Published
+//  Description: Returns a const pointer to the vertex data for the
+//               indicated array, for application code to directly
+//               examine (but not modify) the underlying vertex data.
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_uchar qpGeomVertexData::
+get_array_data(int array) const {
+  CDReader cdata(_cycler);
+  nassertr(array >= 0 && array < (int)cdata->_arrays.size(), CPTA_uchar());
+  return cdata->_arrays[array];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::CData::Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexData::CData::
+CData() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::CData::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexData::CData::
+CData(const qpGeomVertexData::CData &copy) :
+  _arrays(copy._arrays)
+{
+}
+
+INLINE ostream &
+operator << (ostream &out, const qpGeomVertexData &obj) {
+  obj.output(out);
+  return out;
+}

+ 650 - 0
panda/src/gobj/qpgeomVertexData.cxx

@@ -0,0 +1,650 @@
+// Filename: qpgeomVertexData.cxx
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomVertexData.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "pset.h"
+
+TypeHandle qpGeomVertexData::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::Default Constructor
+//       Access: Private
+//  Description: Constructs an invalid object.  This is only used when
+//               reading from the bam file.
+////////////////////////////////////////////////////////////////////
+qpGeomVertexData::
+qpGeomVertexData() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexData::
+qpGeomVertexData(const qpGeomVertexFormat *format) :
+  _format(format)
+{
+  nassertv(_format->is_registered());
+
+  // Create some empty arrays as required by the format.
+  CDWriter cdata(_cycler);
+  cdata->_arrays.insert(cdata->_arrays.end(), _format->get_num_arrays(), 
+                        PTA_uchar());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexData::
+qpGeomVertexData(const qpGeomVertexData &copy) :
+  TypedWritableReferenceCount(copy),
+  _format(copy._format),
+  _cycler(copy._cycler)  
+{
+}
+  
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::Copy Assignment Operator
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+operator = (const qpGeomVertexData &copy) {
+  TypedWritableReferenceCount::operator = (copy);
+  _format = copy._format;
+  _cycler = copy._cycler;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexData::
+~qpGeomVertexData() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::get_num_vertices
+//       Access: Published
+//  Description: Returns the number of vertices stored within all the
+//               arrays.  All arrays store data for the same n
+//               vertices.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexData::
+get_num_vertices() const {
+  CDReader cdata(_cycler);
+  nassertr(_format->get_num_arrays() == (int)cdata->_arrays.size(), 0);
+  if (_format->get_num_arrays() == 0) {
+    // No arrays means no vertices.  Weird but legal.
+    return 0;
+  }
+
+  // Look up the answer on the first array (since any array will do).
+  int stride = _format->get_array(0)->get_stride();
+  return cdata->_arrays[0].size() / stride;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::set_num_vertices
+//       Access: Published
+//  Description: Sets the length of the array to n vertices in all of
+//               the various arrays (presumably by adding vertices).
+//               The new vertex data is uninitialized.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+set_num_vertices(int n) {
+  CDWriter cdata(_cycler);
+  nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
+
+  for (size_t i = 0; i < cdata->_arrays.size(); i++) {
+    int stride = _format->get_array(i)->get_stride();
+    int delta = n - (cdata->_arrays[i].size() / stride);
+
+    if (delta != 0) {
+      if (cdata->_arrays[i].get_ref_count() > 1) {
+        // Copy-on-write: the array is already reffed somewhere else,
+        // so we're just going to make a copy.
+        PTA_uchar new_array;
+        new_array.reserve(n * stride);
+        new_array.insert(new_array.end(), n * stride, uchar());
+        memcpy(new_array, cdata->_arrays[i], 
+               min((size_t)(n * stride), cdata->_arrays[i].size()));
+        cdata->_arrays[i] = new_array;
+
+      } else {
+        // We've got the only reference to the array, so we can change
+        // it directly.
+        if (delta > 0) {
+          cdata->_arrays[i].insert(cdata->_arrays[i].end(), delta * stride, uchar());
+          
+        } else {
+          cdata->_arrays[i].erase(cdata->_arrays[i].begin() + n * stride, 
+                                  cdata->_arrays[i].end());
+        }
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::clear_vertices
+//       Access: Published
+//  Description: Removes all of the vertices from the arrays;
+//               functionally equivalent to set_num_vertices(0) (but
+//               faster).
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+clear_vertices() {
+  CDWriter cdata(_cycler);
+  nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
+
+  Arrays::iterator ai;
+  for (ai = cdata->_arrays.begin();
+       ai != cdata->_arrays.end();
+       ++ai) {
+    (*ai).clear();
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::modify_array_data
+//       Access: Published
+//  Description: Returns a modifiable pointer to the indicated vertex
+//               array, so that application code may directly
+//               manipulate the vertices.  You should avoid changing
+//               the length of this array, since all of the arrays
+//               should be kept in sync--use add_vertices() instead.
+////////////////////////////////////////////////////////////////////
+PTA_uchar qpGeomVertexData::
+modify_array_data(int array) {
+  // Perform copy-on-write: if the reference count on the vertex data
+  // is greater than 1, assume some other GeomVertexData has the same
+  // pointer, so make a copy of it first.
+
+  CDWriter cdata(_cycler);
+  nassertr(array >= 0 && array < (int)cdata->_arrays.size(), PTA_uchar());
+
+  if (cdata->_arrays[array].get_ref_count() > 1) {
+    PTA_uchar orig_data = cdata->_arrays[array];
+    cdata->_arrays[array] = PTA_uchar();
+    cdata->_arrays[array].v() = orig_data.v();
+  }
+  return cdata->_arrays[array];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::set_array_data
+//       Access: Published
+//  Description: Replaces the indicated vertex data array with
+//               a completely new array.  You should be careful that
+//               the new array has the same length as the old one,
+//               unless you know what you are doing.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+set_array_data(int array, PTA_uchar array_data) {
+  CDWriter cdata(_cycler);
+  nassertv(array >= 0 && array < (int)cdata->_arrays.size());
+  cdata->_arrays[array] = array_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::set_data
+//       Access: Published
+//  Description: Sets the nth vertex to a particular value.  Query the
+//               format to get the array index and data_type
+//               parameters for the particular data type you want to
+//               set.
+//
+//               This flavor of set_data() accepts a generic float
+//               array and a specific number of dimensions.  The new
+//               data will be copied from the num_values elements
+//               of data.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+set_data(int array, const qpGeomVertexDataType *data_type,
+         int vertex, const float *data, int num_values) {
+  int stride = _format->get_array(array)->get_stride();
+  int element = vertex * stride + data_type->get_start();
+
+  {
+    CDReader cdata(_cycler);
+    int array_size = (int)cdata->_arrays[array].size();
+    if (element + data_type->get_total_bytes() > array_size) {
+      // Whoops, we need more vertices!
+      set_num_vertices(vertex + 1);
+    }
+  }
+
+  PTA_uchar array_data = modify_array_data(array);
+  nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
+
+  switch (data_type->get_numeric_type()) {
+  case qpGeomVertexDataType::NT_uint8:
+    {
+      nassertv(num_values <= data_type->get_num_values());
+      for (int i = 0; i < num_values; i++) {
+        int value = (int)(data[i] * 255.0f);
+        *(unsigned char *)&array_data[element] = value;
+        element += 1;
+      }
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_packed_argb:
+    {
+      nassertv(num_values == 4);
+      *(PN_uint32 *)&array_data[element] = pack_argb(data);
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_float:
+    nassertv(num_values == data_type->get_num_values());
+    memcpy(&array_data[element], data, data_type->get_total_bytes());
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::get_data
+//       Access: Published
+//  Description: Returns the data associated with the nth vertex for a
+//               particular value.  Query the format to get the array
+//               index and data_type parameters for the particular
+//               data type you want to get.
+//
+//               This flavor of get_data() copies its data into a
+//               generic float array.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+get_data(int array, const qpGeomVertexDataType *data_type,
+         int vertex, float *data, int num_values) const {
+  CPTA_uchar array_data = get_array_data(array);
+  int stride = _format->get_array(array)->get_stride();
+  int element = vertex * stride + data_type->get_start();
+  nassertv(element >= 0 && element + data_type->get_total_bytes() <= (int)array_data.size());
+
+  switch (data_type->get_numeric_type()) {
+  case qpGeomVertexDataType::NT_uint8:
+    {
+      nassertv(num_values <= data_type->get_num_values());
+      for (int i = 0; i < num_values; i++) {
+        int value = *(unsigned char *)&array_data[element];
+        element += 1;
+        data[i] = (float)value / 255.0f;
+      }
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_packed_argb:
+    {
+      nassertv(num_values == 4);
+      unpack_argb(data, *(PN_uint32 *)&array_data[element]);
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_float:
+    nassertv(num_values <= data_type->get_num_values());
+    memcpy(data, &array_data[element], num_values * sizeof(PN_float32));
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::convert_to
+//       Access: Published
+//  Description: Matches up the data types of this format with the
+//               data types of the other format by name, and copies
+//               the data vertex-by-vertex to a new set of data arrays
+//               in the new format.
+////////////////////////////////////////////////////////////////////
+PT(qpGeomVertexData) qpGeomVertexData::
+convert_to(const qpGeomVertexFormat *new_format) const {
+  int num_vertices = get_num_vertices();
+
+  PT(qpGeomVertexData) new_data = new qpGeomVertexData(new_format);
+
+  pset<int> done_arrays;
+
+  int num_arrays = _format->get_num_arrays();
+  int array;
+
+  // First, check to see if any arrays can be simply appropriated for
+  // the new format, without changing the data.
+  for (array = 0; array < num_arrays; ++array) {
+    const qpGeomVertexArrayFormat *array_format = 
+      _format->get_array(array);
+
+    bool array_done = false;
+
+    int new_num_arrays = new_format->get_num_arrays();
+    for (int new_array = 0; 
+         new_array < new_num_arrays && !array_done; 
+         ++new_array) {
+      const qpGeomVertexArrayFormat *new_array_format = 
+        new_format->get_array(new_array);
+      if (new_array_format->is_data_subset_of(*array_format)) {
+        // Great!  Just use the same data for this one.
+        new_data->set_array_data(new_array, (PTA_uchar &)get_array_data(array));
+        array_done = true;
+
+        done_arrays.insert(new_array);
+      }
+    }
+  }
+
+  // Now make sure the arrays we didn't share are all filled in.
+  new_data->set_num_vertices(num_vertices);
+
+  // Now go back through and copy any data that's left over.
+  for (array = 0; array < num_arrays; ++array) {
+    CPTA_uchar array_data = get_array_data(array);
+    const qpGeomVertexArrayFormat *array_format = 
+      _format->get_array(array);
+    int num_data_types = array_format->get_num_data_types();
+    for (int di = 0; di < num_data_types; ++di) {
+      const qpGeomVertexDataType *data_type = array_format->get_data_type(di);
+
+      int new_array = new_format->get_array_with(data_type->get_name());
+      if (new_array >= 0 && done_arrays.count(new_array) == 0) {
+        // The data type exists in the new format; we have to copy it.
+        PTA_uchar new_array_data = new_data->modify_array_data(new_array);
+        const qpGeomVertexArrayFormat *new_array_format = 
+          new_format->get_array(new_array);
+        const qpGeomVertexDataType *new_data_type = 
+          new_array_format->get_data_type(data_type->get_name());
+
+        new_data_type->copy_records
+          (new_array_data + new_data_type->get_start(), 
+           new_array_format->get_stride(),
+           array_data + data_type->get_start(), array_format->get_stride(),
+           data_type, num_vertices);
+      }
+    }
+  }
+
+  return new_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+output(ostream &out) const {
+  out << get_num_vertices() << ": " << *get_format();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::write
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+write(ostream &out, int indent_level) const {
+  _format->write_with_data(out, indent_level, this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::get_array_info
+//       Access: Public
+//  Description: A convenience function to collect together the
+//               important parts of the array data for rendering.
+//               Given the name of a data type, fills in the start of
+//               the array, the number of floats for each vertex, the
+//               starting bytes number, and the number of bytes to
+//               increment for each consecutive vertex.
+//
+//               The return value is true if the named array data
+//               exists in this record, or false if it does not (in
+//               which case none of the output parameters are valid).
+////////////////////////////////////////////////////////////////////
+bool qpGeomVertexData::
+get_array_info(const InternalName *name, CPTA_uchar &array_data,
+               int &num_components, 
+               qpGeomVertexDataType::NumericType &numeric_type, 
+               int &start, int &stride) const {
+  int array_index;
+  const qpGeomVertexDataType *data_type;
+  if (_format->get_array_info(name, array_index, data_type)) {
+    CDReader cdata(_cycler);
+    array_data = cdata->_arrays[array_index];
+    num_components = data_type->get_num_components();
+    numeric_type = data_type->get_numeric_type();
+    start = data_type->get_start();
+    stride = _format->get_array(array_index)->get_stride();
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::to_vec2
+//       Access: Public, Static
+//  Description: Converts a data element of arbitrary number of
+//               dimensions (1 - 4) into a vec2 in a sensible way.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+to_vec2(LVecBase2f &vec, const float *data, int num_values) {
+  switch (num_values) {
+  case 1:
+    vec.set(data[0], 0.0f);
+    break;
+    
+  case 2:
+  case 3:
+    vec.set(data[0], data[1]);
+    break;
+    
+  default:  // 4 or more.
+    vec.set(data[0] / data[3], data[1] / data[3]);
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::to_vec3
+//       Access: Public, Static
+//  Description: Converts a data element of arbitrary number of
+//               dimensions (1 - 4) into a vec3 in a sensible way.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+to_vec3(LVecBase3f &vec, const float *data, int num_values) {
+  switch (num_values) {
+  case 1:
+    vec.set(data[0], 0.0f, 0.0f);
+    break;
+    
+  case 2:
+    vec.set(data[0], data[1], 0.0f);
+    break;
+    
+  case 3:
+    vec.set(data[0], data[1], data[2]);
+    break;
+    
+  default:  // 4 or more.
+    vec.set(data[0] / data[3], data[1] / data[3], data[2] / data[3]);
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::to_vec4
+//       Access: Public, Static
+//  Description: Converts a data element of arbitrary number of
+//               dimensions (1 - 4) into a vec4 in a sensible way.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+to_vec4(LVecBase4f &vec, const float *data, int num_values) {
+  switch (num_values) {
+  case 1:
+    vec.set(data[0], 0.0f, 0.0f, 1.0f);
+    break;
+    
+  case 2:
+    vec.set(data[0], data[1], 0.0f, 1.0f);
+    break;
+    
+  case 3:
+    vec.set(data[0], data[1], data[2], 1.0f);
+    break;
+    
+  default:  // 4 or more.
+    vec.set(data[0], data[1], data[2], data[3]);
+    break;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::pack_argb
+//       Access: Public, Static
+//  Description: Packs four floats, stored R, G, B, A, into a
+//               packed_argb value.
+////////////////////////////////////////////////////////////////////
+unsigned int qpGeomVertexData::
+pack_argb(const float data[4]) {
+  unsigned int r = ((unsigned int)(data[0] * 255.0f)) & 0xff;
+  unsigned int g = ((unsigned int)(data[1] * 255.0f)) & 0xff;
+  unsigned int b = ((unsigned int)(data[2] * 255.0f)) & 0xff;
+  unsigned int a = ((unsigned int)(data[3] * 255.0f)) & 0xff;
+  return ((a << 24) | (r << 16) | (g << 8) | b);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::unpack_argb
+//       Access: Public, Static
+//  Description: Unpacks a packed_argb value into four floats, stored
+//               R, G, B, A.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+unpack_argb(float data[4], unsigned int packed_argb) {
+  data[0] = (float)((packed_argb >> 16) & 0xff) / 255.0f;
+  data[1] = (float)((packed_argb >> 8) & 0xff) / 255.0f;
+  data[2] = (float)(packed_argb & 0xff) / 255.0f;
+  data[3] = (float)((packed_argb >> 24) & 0xff) / 255.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeomVertexData.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  TypedWritable::write_datagram(manager, dg);
+
+  manager->write_cdata(dg, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeomVertexData is encountered
+//               in the Bam file.  It should create the qpGeomVertexData
+//               and extract its information from the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomVertexData::
+make_from_bam(const FactoryParams &params) {
+  qpGeomVertexData *object = new qpGeomVertexData;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeomVertexData.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  TypedWritable::fillin(scan, manager);
+
+  manager->read_cdata(scan, _cycler);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::CData::make_copy
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData *qpGeomVertexData::CData::
+make_copy() const {
+  return new CData(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::CData::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::CData::
+write_datagram(BamWriter *manager, Datagram &dg) const {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::CData::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexData::CData::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = CycleData::complete_pointers(p_list, manager);
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexData::CData::fillin
+//       Access: Public, Virtual
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeomVertexData.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexData::CData::
+fillin(DatagramIterator &scan, BamReader *manager) {
+}

+ 155 - 0
panda/src/gobj/qpgeomVertexData.h

@@ -0,0 +1,155 @@
+// Filename: qpgeomVertexData.h
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMVERTEXDATA_H
+#define qpGEOMVERTEXDATA_H
+
+#include "pandabase.h"
+#include "typedWritableReferenceCount.h"
+#include "qpgeomVertexFormat.h"
+#include "qpgeomVertexDataType.h"
+#include "internalName.h"
+#include "cycleData.h"
+#include "cycleDataReader.h"
+#include "cycleDataWriter.h"
+#include "pipelineCycler.h"
+#include "pointerTo.h"
+#include "pmap.h"
+#include "pvector.h"
+#include "pta_uchar.h"
+
+class FactoryParams;
+class qpGeomVertexDataType;
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomVertexData
+// Description : This defines the actual numeric vertex data stored in
+//               a Geom, in the structure defined by a particular
+//               GeomVertexFormat object.
+//
+//               The data consists of one or more arrays of floats.
+//               Typically, there will be only one array per Geom, and
+//               the various data types defined in the
+//               GeomVertexFormat will be interleaved throughout that
+//               array.  However, it is possible to have multiple
+//               different arrays, with different combinations of data
+//               types through each one.
+//
+//               However the data is distributed, the effect is of a
+//               table of vertices, with a value for each of the
+//               GeomVertexFormat's data types, stored for each
+//               vertex.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomVertexData : public TypedWritableReferenceCount {
+private:
+  qpGeomVertexData();
+PUBLISHED:
+  qpGeomVertexData(const qpGeomVertexFormat *format);
+  qpGeomVertexData(const qpGeomVertexData &copy);
+  void operator = (const qpGeomVertexData &copy);
+  virtual ~qpGeomVertexData();
+
+  INLINE const qpGeomVertexFormat *get_format() const;
+
+  int get_num_vertices() const;
+  void set_num_vertices(int n);
+  void clear_vertices();
+
+  INLINE int get_num_arrays() const;
+  INLINE CPTA_uchar get_array_data(int array) const;
+  PTA_uchar modify_array_data(int array);
+  void set_array_data(int array, PTA_uchar array_data);
+
+  void set_data(int array, const qpGeomVertexDataType *data_type,
+                int vertex, const float *data, int num_values);
+  void get_data(int array, const qpGeomVertexDataType *data_type,
+                int vertex, float *data, int num_values) const;
+
+  PT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level = 0) const;
+
+public:
+  bool get_array_info(const InternalName *name, CPTA_uchar &array_data,
+                      int &num_components,
+                      qpGeomVertexDataType::NumericType &numeric_type, 
+                      int &start, int &stride) const;
+
+  static void to_vec2(LVecBase2f &vec, const float *data, int num_values);
+  static void to_vec3(LVecBase3f &vec, const float *data, int num_values);
+  static void to_vec4(LVecBase4f &vec, const float *data, int num_values);
+
+  static unsigned int pack_argb(const float data[4]);
+  static void unpack_argb(float data[4], unsigned int packed_argb);
+
+private:
+  typedef pvector<PTA_uchar> Arrays;
+
+  CPT(qpGeomVertexFormat) _format;
+
+  // This is the data that must be cycled between pipeline stages.
+  class EXPCL_PANDA CData : public CycleData {
+  public:
+    INLINE CData();
+    INLINE CData(const CData &copy);
+    virtual CycleData *make_copy() const;
+    virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
+    virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
+    virtual void fillin(DatagramIterator &scan, BamReader *manager);
+
+    Arrays _arrays;
+  };
+
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "qpGeomVertexData",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+};
+
+INLINE ostream &operator << (ostream &out, const qpGeomVertexData &obj);
+
+#include "qpgeomVertexData.I"
+
+#endif

+ 221 - 0
panda/src/gobj/qpgeomVertexDataType.I

@@ -0,0 +1,221 @@
+// Filename: qpgeomVertexDataType.I
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomVertexDataType::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexDataType::
+qpGeomVertexDataType(const qpGeomVertexDataType &copy) :
+  _name(copy._name),
+  _num_components(copy._num_components),
+  _num_values(copy._num_values),
+  _numeric_type(copy._numeric_type),
+  _start(copy._start),
+  _component_bytes(copy._component_bytes),
+  _total_bytes(copy._total_bytes)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::Copy Assignment Operator
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexDataType::
+operator = (const qpGeomVertexDataType &copy) {
+  _name = copy._name;
+  _num_components = copy._num_components;
+  _num_values = copy._num_values;
+  _numeric_type = copy._numeric_type;
+  _start = copy._start;
+  _component_bytes = copy._component_bytes;
+  _total_bytes = copy._total_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_name
+//       Access: Published
+//  Description: Returns the name of this particular data field,
+//               e.g. "vertex" or "normal".  The name may be a
+//               user-defined string, or it may be one of the standard
+//               system-defined field types.  Only the system-defined
+//               field types are used for the actual rendering.
+////////////////////////////////////////////////////////////////////
+INLINE const InternalName *qpGeomVertexDataType::
+get_name() const {
+  return _name;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_num_components
+//       Access: Published
+//  Description: Returns the number of components of each data type:
+//               the number of instances of the NumericType in each
+//               element.  This is usually, but not always, the same
+//               thing as get_num_values().
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexDataType::
+get_num_components() const {
+  return _num_components;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_num_values
+//       Access: Published
+//  Description: Returns the number of numeric values of each data
+//               type: the number of distinct numeric values that go
+//               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
+//               per component.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexDataType::
+get_num_values() const {
+  return _num_values;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_numeric_type
+//       Access: Published
+//  Description: Returns the token representing the numeric type of
+//               the data storage.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexDataType::NumericType qpGeomVertexDataType::
+get_numeric_type() const {
+  return _numeric_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_start
+//       Access: Published
+//  Description: Returns the byte within the array record at which
+//               this data type starts.  This can be set to non-zero
+//               to implement interleaved arrays.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexDataType::
+get_start() const {
+  return _start;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_component_bytes
+//       Access: Published
+//  Description: Returns the number of bytes used by each component
+//               (that is, by one element of the numeric type).
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexDataType::
+get_component_bytes() const {
+  return _component_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_total_bytes
+//       Access: Published
+//  Description: Returns the number of bytes used by the data type:
+//               component_bytes * num_components.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexDataType::
+get_total_bytes() const {
+  return _total_bytes;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::overlaps_with
+//       Access: Published
+//  Description: Returns true if this data type overlaps with any of
+//               the bytes in the indicated range, false if it does
+//               not.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomVertexDataType::
+overlaps_with(int start_byte, int num_bytes) const {
+  return (_start < start_byte + num_bytes &&
+          _start + _total_bytes > start_byte);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::compare_to
+//       Access: Public
+//  Description: This is used to unquify data types, and hence
+//               formats, for the GeomVertexFormat registry.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexDataType::
+compare_to(const qpGeomVertexDataType &other) const {
+  if (_name != other._name) {
+    return _name < other._name ? -1 : 1;
+  }
+  if (_num_components != other._num_components) {
+    return _num_components - other._num_components;
+  }
+  if (_numeric_type != other._numeric_type) {
+    return (int)_numeric_type - (int)other._numeric_type;
+  }
+  if (_start != other._start) {
+    return _start - other._start;
+  }
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::operator ==
+//       Access: Public
+//  Description: Returns true if the two data types are exactly
+//               equivalent, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomVertexDataType::
+operator == (const qpGeomVertexDataType &other) const {
+  return compare_to(other) == 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::operator !=
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomVertexDataType::
+operator != (const qpGeomVertexDataType &other) const {
+  return compare_to(other) != 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::operator <
+//       Access: Public
+//  Description: This is used to put data types in order within a
+//               particular GeomVertexArrayFormat.  Note that it is
+//               *not* in the same space as operator == and operator
+//               !=.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomVertexDataType::
+operator < (const qpGeomVertexDataType &other) const {
+  if (_start != other._start) { 
+    return _start < other._start;
+  }
+  if (_total_bytes < other._total_bytes) {
+    return _total_bytes < other._total_bytes;
+  }
+  return 0;
+}
+
+INLINE ostream &
+operator << (ostream &out, const qpGeomVertexDataType &obj) {
+  obj.output(out);
+  return out;
+}

+ 309 - 0
panda/src/gobj/qpgeomVertexDataType.cxx

@@ -0,0 +1,309 @@
+// Filename: qpgeomVertexDataType.cxx
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomVertexDataType.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexDataType::
+qpGeomVertexDataType(const InternalName *name, int num_components,
+                     NumericType numeric_type, int start) :
+  _name(name),
+  _num_components(num_components),
+  _num_values(num_components),
+  _numeric_type(numeric_type),
+  _start(start)
+{
+  nassertv(num_components > 0 && start >= 0);
+
+  switch (numeric_type) {
+  case NT_uint8:
+    _component_bytes = 1;
+    break;
+
+  case NT_packed_argb:
+    _component_bytes = 4;  // sizeof(PN_uint32)
+    _num_values *= 4;
+    break;
+
+  case NT_float:
+    _component_bytes = 4;  // sizeof(PN_float32)
+    break;
+  }
+
+  _total_bytes = _component_bytes * _num_components;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::error named constructor
+//       Access: Published
+//  Description: Returns a data type specifically to represent an
+//               error condition.
+////////////////////////////////////////////////////////////////////
+const qpGeomVertexDataType &qpGeomVertexDataType::
+error() {
+  static qpGeomVertexDataType error_result
+    (InternalName::get_error(), 1, NT_uint8, 0);
+  return error_result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+output(ostream &out) const {
+  out << *get_name() << "(" << get_num_components() << ")";
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::copy_records
+//       Access: Published
+//  Description: Copies and converts from one data type to another.
+//               Copies the num_records records from the "from"
+//               buffer, encoded with from_type, to the "to" buffer,
+//               encoded with this current type, converting each one
+//               as necessary.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+copy_records(unsigned char *to, int to_stride,
+             const unsigned char *from, int from_stride,
+             const qpGeomVertexDataType *from_type,
+             int num_records) const {
+  // Temp for debugging.
+  static ConfigVariableBool do_copy_generic("copy-generic", false);
+  if (do_copy_generic) {
+    copy_generic(to, to_stride, from, from_stride, from_type, num_records);
+    return;
+  }
+
+  if (get_numeric_type() == from_type->get_numeric_type() &&
+      get_num_values() == from_type->get_num_values()) {
+      // An easy case.
+    copy_no_convert(to, to_stride, from, from_stride, from_type, num_records);
+
+  } else if (get_numeric_type() == NT_uint8 && from_type->get_numeric_type() == NT_packed_argb &&
+             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_uint8 &&
+             get_num_values() == from_type->get_num_values()) {
+    copy_uint8_to_argb(to, to_stride, from, from_stride, from_type, num_records);
+  } else {
+    copy_generic(to, to_stride, from, from_stride, from_type, num_records);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::copy_no_convert
+//       Access: Private
+//  Description: Quickly copies data without the need to convert it.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+copy_no_convert(unsigned char *to, int to_stride,
+                const unsigned char *from, int from_stride,
+                const qpGeomVertexDataType *from_type,
+                int num_records) const {
+  if (to_stride == _total_bytes && from_stride == _total_bytes) {
+    // Fantastic!  It's just a linear array of this one data type.
+    // Copy the whole thing all at once.
+    memcpy(to, from, num_records * _total_bytes);
+
+  } else {
+    // Ok, it's interleaved in with other data.  Copy them one record
+    // at a time.
+    while (num_records > 0) {
+      memcpy(to, from, _total_bytes);
+      to += to_stride;
+      from += from_stride;
+      num_records--;
+    }
+  }
+}
+  
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::copy_argb_to_uint8
+//       Access: Private
+//  Description: Converts packed_argb to uint8-based r, g, b, a.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+copy_argb_to_uint8(unsigned char *to, int to_stride,
+                   const unsigned char *from, int from_stride,
+                   const qpGeomVertexDataType *from_type,
+                   int num_records) const {
+  while (num_records > 0) {
+    PN_uint32 packed_argb = *(const PN_uint32 *)from;
+    to[0] = ((packed_argb >> 16) & 0xff);
+    to[1] = ((packed_argb >> 8) & 0xff);
+    to[2] = (packed_argb & 0xff);
+    to[3] = ((packed_argb >> 24) & 0xff);
+
+    to += to_stride;
+    from += from_stride;
+    num_records--;
+  }
+}
+  
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::copy_uint8_to_argb
+//       Access: Private
+//  Description: Converts uint8-based r, g, b, a to packed_argb.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+copy_uint8_to_argb(unsigned char *to, int to_stride,
+                   const unsigned char *from, int from_stride,
+                   const qpGeomVertexDataType *from_type,
+                   int num_records) const {
+  while (num_records > 0) {
+    PN_uint32 packed_argb = ((from[3] << 24) | (from[0] << 16) | (from[1] << 8) | from[2]);
+    *(PN_uint32 *)to = packed_argb;
+
+    to += to_stride;
+    from += from_stride;
+    num_records--;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::copy_generic
+//       Access: Private
+//  Description: A more general anything-to-anything copy (somewhat
+//               more expensive than the above).
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+copy_generic(unsigned char *to, int to_stride,
+             const unsigned char *from, int from_stride,
+             const qpGeomVertexDataType *from_type,
+             int num_records) const {
+  int num_values_to_copy = min(get_num_values(), from_type->get_num_values());
+  int num_values_to_fill = get_num_values() - num_values_to_copy;
+
+  while (num_records > 0) {
+    int vi = 0;
+    while (vi < num_values_to_copy) {
+      float value = from_type->get_value(from, vi);
+      set_value(to, vi, value);
+      ++vi;
+    }
+    while (vi < num_values_to_fill) {
+      set_value(to, vi, 0.0f);
+      ++vi;
+    }
+
+    to += to_stride;
+    from += from_stride;
+    num_records--;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::get_value
+//       Access: Private
+//  Description: Returns the nth value of the data type, expressed as
+//               a float.
+////////////////////////////////////////////////////////////////////
+float qpGeomVertexDataType::
+get_value(const unsigned char *data, int n) const {
+  switch (get_numeric_type()) {
+  case NT_uint8:
+    return (float)data[n] / 255.0f;
+
+  case qpGeomVertexDataType::NT_packed_argb:
+    {
+      int element = n / 4;
+      const PN_uint32 *int_array = (const PN_uint32 *)data;
+
+      PN_uint32 packed_argb = int_array[element];
+      switch (n % 4) {
+      case 0:
+        return (float)((packed_argb >> 16) & 0xff) / 255.0f;
+      case 1:
+        return (float)((packed_argb >> 8) & 0xff) / 255.0f;
+      case 2:
+        return (float)(packed_argb & 0xff) / 255.0f;
+      case 3:
+        return (float)((packed_argb >> 24) & 0xff) / 255.0f;
+      }
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_float:
+    {
+      const PN_float32 *float_array = (const PN_float32 *)data;
+      return float_array[n];
+    }
+  }
+
+  return 0.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexDataType::set_value
+//       Access: Private
+//  Description: Modifies the nth value of the data type.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexDataType::
+set_value(unsigned char *data, int n, float value) const {
+  switch (get_numeric_type()) {
+  case NT_uint8:
+    data[n] = (int)(value * 255.0f);
+    break;
+
+  case qpGeomVertexDataType::NT_packed_argb:
+    {
+      int element = n / 4;
+
+      union {
+        PN_uint32 _packed_argb;
+        struct {
+          unsigned char _a;
+          unsigned char _r;
+          unsigned char _g;
+          unsigned char _b;
+        } _argb;
+      } color;
+
+      PN_uint32 *int_array = (PN_uint32 *)data;
+      color._packed_argb = int_array[element];
+      switch (n % 4) {
+      case 0:
+        color._argb._r = (int)(value * 255.0f);
+        break;
+      case 1:
+        color._argb._g = (int)(value * 255.0f);
+        break;
+      case 2:
+        color._argb._b = (int)(value * 255.0f);
+        break;
+      case 3:
+        color._argb._a = (int)(value * 255.0f);
+        break;
+      }
+      int_array[element] = color._packed_argb;
+    }
+    break;
+
+  case qpGeomVertexDataType::NT_float:
+    PN_float32 *float_array = (PN_float32 *)data;
+    float_array[n] = value;
+    break;
+  }
+}

+ 109 - 0
panda/src/gobj/qpgeomVertexDataType.h

@@ -0,0 +1,109 @@
+// Filename: qpgeomVertexDataType.h
+// Created by:  drose (06Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMVERTEXDATATYPE_H
+#define qpGEOMVERTEXDATATYPE_H
+
+#include "pandabase.h"
+#include "internalName.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomVertexDataType
+// Description : This defines how a single data type is interleaved
+//               within a vertex array stored within a Geom.  The
+//               GeomVertexArrayFormat class maintains a list of these
+//               to completely define a particular array structure.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomVertexDataType {
+PUBLISHED:
+  enum NumericType {
+    NT_uint8,
+    NT_packed_argb,  // DirectX style
+    NT_float,
+  };
+
+  INLINE qpGeomVertexDataType(const InternalName *name, int num_components,
+                              NumericType numeric_type, int start);
+  INLINE qpGeomVertexDataType(const qpGeomVertexDataType &copy);
+  INLINE void operator = (const qpGeomVertexDataType &copy);
+
+  static const qpGeomVertexDataType &error();
+
+  INLINE const InternalName *get_name() const;
+  INLINE int get_num_components() const;
+  INLINE int get_num_values() const;
+  INLINE NumericType get_numeric_type() const;
+  INLINE int get_start() const;
+  INLINE int get_component_bytes() const;
+  INLINE int get_total_bytes() const;
+
+  INLINE bool overlaps_with(int start_byte, int num_bytes) const;
+
+  void output(ostream &out) const;
+
+public:
+  INLINE int compare_to(const qpGeomVertexDataType &other) const;
+  INLINE bool operator == (const qpGeomVertexDataType &other) const;
+  INLINE bool operator != (const qpGeomVertexDataType &other) const;
+  INLINE bool operator < (const qpGeomVertexDataType &other) const;
+
+  void copy_records(unsigned char *to, int to_stride,
+                    const unsigned char *from, int from_stride,
+                    const qpGeomVertexDataType *from_type,
+                    int num_records) const;
+
+private:
+  void copy_no_convert(unsigned char *to, int to_stride,
+                       const unsigned char *from, int from_stride,
+                       const qpGeomVertexDataType *from_type,
+                       int num_records) const;
+  void copy_argb_to_uint8(unsigned char *to, int to_stride,
+                          const unsigned char *from, int from_stride,
+                          const qpGeomVertexDataType *from_type,
+                          int num_records) const;
+  void copy_uint8_to_argb(unsigned char *to, int to_stride,
+                          const unsigned char *from, int from_stride,
+                          const qpGeomVertexDataType *from_type,
+                          int num_records) const;
+
+  void copy_generic(unsigned char *to, int to_stride,
+                    const unsigned char *from, int from_stride,
+                    const qpGeomVertexDataType *from_type,
+                    int num_records) const;
+
+  float get_value(const unsigned char *data, int n) const;
+  void set_value(unsigned char *data, int n, float value) const;
+
+private:
+  CPT(InternalName) _name;
+  int _num_components;
+  int _num_values;
+  NumericType _numeric_type;
+  int _start;
+  int _component_bytes;
+  int _total_bytes;
+};
+
+INLINE ostream &operator << (ostream &out, const qpGeomVertexDataType &obj);
+
+#include "qpgeomVertexDataType.I"
+
+#endif

+ 260 - 0
panda/src/gobj/qpgeomVertexFormat.I

@@ -0,0 +1,260 @@
+// Filename: qpgeomVertexFormat.I
+// Created by:  drose (07Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+INLINE ostream &
+operator << (ostream &out, const qpGeomVertexFormat &obj) {
+  obj.output(out);
+  return out;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::is_registered
+//       Access: Published
+//  Description: Returns true if this format has been registered,
+//               false if it has not.  It may not be used for a Geom
+//               until it has been registered, but once registered, it
+//               may no longer be modified.
+////////////////////////////////////////////////////////////////////
+INLINE bool qpGeomVertexFormat::
+is_registered() const {
+  return _is_registered;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::register_format
+//       Access: Published, Static
+//  Description: Adds the indicated format to the registry, if there
+//               is not an equivalent format already there; in either
+//               case, returns the pointer to the equivalent format
+//               now in the registry.
+//
+//               This must be called before a format may be used in a
+//               Geom.  After this call, you should discard the
+//               original pointer you passed in (which may or may not
+//               now be invalid) and let its reference count decrement
+//               normally; you should use only the returned value from
+//               this point on.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexFormat) qpGeomVertexFormat::
+register_format(qpGeomVertexFormat *format) {
+  return get_registry()->register_format(format);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::register_format
+//       Access: Published, Static
+//  Description: This flavor of register_format() implicitly creates a
+//               one-array vertex format from the array definition.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexFormat) qpGeomVertexFormat::
+register_format(qpGeomVertexArrayFormat *format) {
+  return get_registry()->register_format(format);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_num_arrays
+//       Access: Published
+//  Description: Returns the number of individual arrays required by
+//               the format.  If the array data is completely
+//               interleaved, this will be 1; if it is completely
+//               parallel, this will be the same as the number of data
+//               types.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexFormat::
+get_num_arrays() const {
+  return _arrays.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_array
+//       Access: Published
+//  Description: Returns the description of the nth array used by the
+//               format.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexArrayFormat *qpGeomVertexFormat::
+get_array(int array) const {
+  nassertr(array >= 0 && array < (int)_arrays.size(), NULL);
+  return _arrays[array];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with just a
+//               3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3() {
+  return get_registry()->_v3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3n3
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 3-component
+//               normal and a 3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3n3() {
+  return get_registry()->_v3n3;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3t2
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 2-component
+//               texture coordinate pair and a 3-component vertex
+//               position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3t2() {
+  return get_registry()->_v3t2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3n3t2
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 2-component
+//               texture coordinate pair, a 3-component normal, and a
+//               3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3n3t2() {
+  return get_registry()->_v3n3t2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3cp
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a packed
+//               color and a 3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3cp() {
+  return get_registry()->_v3cp;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3n3cp
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a packed
+//               color, a 3-component normal, and a 3-component vertex
+//               position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3n3cp() {
+  return get_registry()->_v3n3cp;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3cpt2
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 2-component
+//               texture coordinate pair, a packed color, and a
+//               3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3cpt2() {
+  return get_registry()->_v3cpt2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3n3cpt2
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 2-component
+//               texture coordinate pair, a packed color, a
+//               3-component normal, and a 3-component vertex
+//               position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3n3cpt2() {
+  return get_registry()->_v3n3cpt2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3c4
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 4-component
+//               color and a 3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3c4() {
+  return get_registry()->_v3c4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3n3c4
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 4-component
+//               color, a 3-component normal, and a 3-component vertex
+//               position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3n3c4() {
+  return get_registry()->_v3n3c4;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3c4t2
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 2-component
+//               texture coordinate pair, a 4-component color, and a
+//               3-component vertex position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3c4t2() {
+  return get_registry()->_v3c4t2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_v3n3c4t2
+//       Access: Published, Static
+//  Description: Returns a standard vertex format with a 2-component
+//               texture coordinate pair, a 4-component color, a
+//               3-component normal, and a 3-component vertex
+//               position.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexFormat *qpGeomVertexFormat::
+get_v3n3c4t2() {
+  return get_registry()->_v3n3c4t2;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_registry
+//       Access: Private
+//  Description: Returns the global registry object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexFormat::Registry *qpGeomVertexFormat::
+get_registry() {
+  if (_registry == (Registry *)NULL) {
+    make_registry();
+  }
+  return _registry;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Registry::register_format
+//       Access: Public
+//  Description: This flavor of register_format() implicitly creates a
+//               one-array vertex format from the array definition.
+////////////////////////////////////////////////////////////////////
+INLINE CPT(qpGeomVertexFormat) qpGeomVertexFormat::Registry::
+register_format(qpGeomVertexArrayFormat *format) {
+  return register_format(new qpGeomVertexFormat(format));
+}

+ 632 - 0
panda/src/gobj/qpgeomVertexFormat.cxx

@@ -0,0 +1,632 @@
+// Filename: qpgeomVertexFormat.cxx
+// Created by:  drose (07Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomVertexFormat.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomMunger.h"
+#include "indent.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+
+qpGeomVertexFormat::Registry *qpGeomVertexFormat::_registry = NULL;
+TypeHandle qpGeomVertexFormat::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexFormat::
+qpGeomVertexFormat() :
+  _is_registered(false)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexFormat::
+qpGeomVertexFormat(qpGeomVertexArrayFormat *array_format) :
+  _is_registered(false)
+{
+  add_array(array_format);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexFormat::
+qpGeomVertexFormat(const qpGeomVertexFormat &copy) :
+  _is_registered(false),
+  _arrays(copy._arrays)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Copy Assignment Operator
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+operator = (const qpGeomVertexFormat &copy) {
+  nassertv(!_is_registered);
+
+  _arrays = copy._arrays;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Destructor
+//       Access: Published, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexFormat::
+~qpGeomVertexFormat() {
+  if (is_registered()) {
+    get_registry()->unregister_format(this);
+  }
+  nassertv(_mungers.empty());
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::modify_array
+//       Access: Published
+//  Description: Returns a modifiable pointer to the indicated array.
+//               This means duplicating it if it is shared or
+//               registered.
+////////////////////////////////////////////////////////////////////
+qpGeomVertexArrayFormat *qpGeomVertexFormat::
+modify_array(int array) {
+  nassertr(!_is_registered, NULL);
+  nassertr(array >= 0 && array < (int)_arrays.size(), NULL);
+
+  if (_arrays[array]->is_registered() ||
+      _arrays[array]->get_ref_count() > 1) {
+    _arrays[array] = new qpGeomVertexArrayFormat(*_arrays[array]);
+  }
+
+  return _arrays[array];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::set_array
+//       Access: Published
+//  Description: Replaces the definition of the indicated array.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+set_array(int array, qpGeomVertexArrayFormat *format) {
+  nassertv(!_is_registered);
+  nassertv(array >= 0 && array < (int)_arrays.size());
+  _arrays[array] = format;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::remove_array
+//       Access: Published
+//  Description: Removes the nth array from the format.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+remove_array(int array) {
+  nassertv(!_is_registered);
+
+  nassertv(array >= 0 && array < (int)_arrays.size());
+  _arrays.erase(_arrays.begin() + array);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::add_array
+//       Access: Published
+//  Description: Adds the indicated array definition to the list of
+//               arrays included within this vertex format definition.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+add_array(qpGeomVertexArrayFormat *array_format) {
+  nassertv(!_is_registered);
+
+  _arrays.push_back(array_format);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::clear_arrays
+//       Access: Published
+//  Description: Removes all of the array definitions from the format
+//               and starts over.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+clear_arrays() {
+  nassertv(!_is_registered);
+
+  _arrays.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_num_data_types
+//       Access: Published
+//  Description: Returns the total number of different data types in
+//               the specification, across all arrays.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexFormat::
+get_num_data_types() const {
+  int num_data_types = 0;
+  Arrays::const_iterator ai;
+  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
+    num_data_types += (*ai)->get_num_data_types();
+  }
+  return num_data_types;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_data_type
+//       Access: Published
+//  Description: Returns the ith data type of the specification,
+//               across all arrays.
+////////////////////////////////////////////////////////////////////
+const qpGeomVertexDataType *qpGeomVertexFormat::
+get_data_type(int i) const {
+  Arrays::const_iterator ai;
+  for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
+    if (i < (*ai)->get_num_data_types()) {
+      return (*ai)->get_data_type(i);
+    }
+    i -= (*ai)->get_num_data_types();
+  }
+
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_array_with
+//       Access: Published
+//  Description: Returns the index number of the array with the
+//               ith data type.
+//
+//               The return value can be passed to get_array_format()
+//               to get the format of the array.  It may also be
+//               passed to GeomVertexData::get_array_data() or
+//               get_data() or set_data() to manipulate the actual
+//               array data.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexFormat::
+get_array_with(int i) const {
+  int array_index = 0;
+  for (array_index = 0; array_index < (int)_arrays.size(); array_index++) {
+    if (i < _arrays[array_index]->get_num_data_types()) {
+      return array_index;
+    }
+    i -= _arrays[array_index]->get_num_data_types();
+  }
+
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_array_with
+//       Access: Published
+//  Description: Returns the index number of the array with the
+//               indicated data type, or -1 if no arrays contained
+//               that name.
+//
+//               The return value can be passed to get_array_format()
+//               to get the format of the array.  It may also be
+//               passed to GeomVertexData::get_array_data() or
+//               get_data() or set_data() to manipulate the actual
+//               array data.
+//
+//               This may only be called after the format has been
+//               registered.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexFormat::
+get_array_with(const InternalName *name) const {
+  nassertr(_is_registered, -1);
+
+  DataTypesByName::const_iterator ai;
+  ai = _data_types_by_name.find(name);
+  if (ai != _data_types_by_name.end()) {
+    return (*ai).second._array_index;
+  }
+  return -1;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_data_type
+//       Access: Published
+//  Description: Returns the specification with the indicated name, or
+//               NULL if the name is not used.  Use get_array_with()
+//               to determine which array this data type is associated
+//               with.
+//
+//               This may only be called after the format has been
+//               registered.
+////////////////////////////////////////////////////////////////////
+const qpGeomVertexDataType *qpGeomVertexFormat::
+get_data_type(const InternalName *name) const {
+  nassertr(_is_registered, NULL);
+
+  DataTypesByName::const_iterator ai;
+  ai = _data_types_by_name.find(name);
+  if (ai != _data_types_by_name.end()) {
+    int array_index = (*ai).second._array_index;
+    int data_type_index = (*ai).second._data_type_index;
+
+    nassertr(array_index >= 0 && array_index < (int)_arrays.size(), NULL);
+    return _arrays[array_index]->get_data_type(data_type_index);
+  }
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+output(ostream &out) const {
+  if (_arrays.empty()) {
+    out << "(empty)";
+
+  } else {
+    Arrays::const_iterator ai;
+    ai = _arrays.begin();
+    out << *(*ai);
+    ++ai;
+    while (ai != _arrays.end()) {
+      out << ", " << *(*ai);
+      ++ai;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::write
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+write(ostream &out, int indent_level) const {
+  for (size_t i = 0; i < _arrays.size(); i++) {
+    indent(out, indent_level)
+      << "Array " << i << ":\n";
+    _arrays[i]->write(out, indent_level + 2);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::write_with_data
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+write_with_data(ostream &out, int indent_level, 
+                const qpGeomVertexData *data) const {
+  indent(out, indent_level)
+    << data->get_num_vertices() << " vertices.\n";
+  for (size_t i = 0; i < _arrays.size(); i++) {
+    CPTA_uchar array_data = data->get_array_data(i);
+    indent(out, indent_level)
+      << "Array " << i << " (" << (void *)array_data.p() << "):\n";
+    _arrays[i]->write_with_data(out, indent_level + 2, data, i);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::get_array_info
+//       Access: Public
+//  Description: Quickly looks up the indicated data type within all
+//               of the nested arrays and sets array_index and
+//               data_type appropriately.  Returns true if the data
+//               type exists in this format, false if it does not.
+//
+//               This may only be called after the format has been
+//               registered.
+////////////////////////////////////////////////////////////////////
+bool qpGeomVertexFormat::
+get_array_info(const InternalName *name, int &array_index,
+               const qpGeomVertexDataType *&data_type) const {
+  nassertr(_is_registered, false);
+
+  DataTypesByName::const_iterator ai;
+  ai = _data_types_by_name.find(name);
+  if (ai != _data_types_by_name.end()) {
+    array_index = (*ai).second._array_index;
+    data_type = _arrays[array_index]->get_data_type((*ai).second._data_type_index);
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::compare_to
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexFormat::
+compare_to(const qpGeomVertexFormat &other) const {
+  if (_arrays.size() != other._arrays.size()) {
+    return (int)_arrays.size() - (int)other._arrays.size();
+  }
+
+  for (size_t i = 0; i < _arrays.size(); i++) {
+    int compare = _arrays[i]->compare_to(*other._arrays[i]);
+    if (compare != 0) {
+      return compare;
+    }
+  }
+
+  return 0;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::make_registry
+//       Access: Private
+//  Description: Returns the global registry object.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+make_registry() {
+  if (_registry == (Registry *)NULL) {
+    _registry = new Registry;
+  }
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::do_register
+//       Access: Private
+//  Description: Called internally when the format is registered.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+do_register() {
+  nassertv(!_is_registered);
+  nassertv(_data_types_by_name.empty());
+  nassertv(_mungers.empty());
+
+  int array = 0;
+  for (array = 0; array < (int)_arrays.size(); ++array) {
+    const qpGeomVertexArrayFormat *array_format = _arrays[array];
+    if (!array_format->is_registered()) {
+      ((qpGeomVertexArrayFormat *)array_format)->do_register();
+    }
+
+    // Now add the names to the index.
+    int num_data_types = array_format->get_num_data_types();
+    for (int i = 0; i < num_data_types; i++) {
+      const qpGeomVertexDataType *data_type = array_format->get_data_type(i);
+      pair<DataTypesByName::iterator, bool> result;
+      result = _data_types_by_name.insert(DataTypesByName::value_type(data_type->get_name(), DataTypeRecord()));
+      if (!result.second) {
+        gobj_cat.warning()
+          << "Data type " << data_type->get_name() << " repeated in format.\n";
+      } else {
+        DataTypeRecord &record = (*result.first).second;
+        record._array_index = array;
+        record._data_type_index = i;
+      }
+    }
+  }
+
+  _is_registered = true;
+}
+ 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::do_unregister
+//       Access: Private
+//  Description: Called internally when the format is unregistered.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+do_unregister() {
+  nassertv(_is_registered);
+  _is_registered = false;
+
+  _data_types_by_name.clear();
+
+  Mungers::iterator mi;
+  for (mi = _mungers.begin(); mi != _mungers.end(); ++mi) {
+    (*mi)->remove_format(this);
+  }
+  _mungers.clear();  
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::register_with_read_factory
+//       Access: Public, Static
+//  Description: Tells the BamReader how to create objects of type
+//               qpGeomVertexFormat.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::write_datagram
+//       Access: Public, Virtual
+//  Description: Writes the contents of this object to the datagram
+//               for shipping out to a Bam file.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+write_datagram(BamWriter *manager, Datagram &dg) {
+  TypedWritableReferenceCount::write_datagram(manager, dg);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::complete_pointers
+//       Access: Public, Virtual
+//  Description: Receives an array of pointers, one for each time
+//               manager->read_pointer() was called in fillin().
+//               Returns the number of pointers processed.
+////////////////////////////////////////////////////////////////////
+int qpGeomVertexFormat::
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
+
+  return pi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::make_from_bam
+//       Access: Protected, Static
+//  Description: This function is called by the BamReader's factory
+//               when a new object of type qpGeomVertexFormat is
+//               encountered in the Bam file.  It should create the
+//               qpGeomVertexFormat and extract its information from
+//               the file.
+////////////////////////////////////////////////////////////////////
+TypedWritable *qpGeomVertexFormat::
+make_from_bam(const FactoryParams &params) {
+  qpGeomVertexFormat *object = new qpGeomVertexFormat;
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  object->fillin(scan, manager);
+
+  return object;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::fillin
+//       Access: Protected
+//  Description: This internal function is called by make_from_bam to
+//               read in all of the relevant data from the BamFile for
+//               the new qpGeomVertexFormat.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::
+fillin(DatagramIterator &scan, BamReader *manager) {
+  TypedWritableReferenceCount::fillin(scan, manager);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Registry::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomVertexFormat::Registry::
+Registry() {
+  _v3 = register_format(new qpGeomVertexArrayFormat
+                        (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float));
+
+  _v3n3 = register_format(new qpGeomVertexArrayFormat
+                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float));
+
+  _v3t2 = register_format(new qpGeomVertexArrayFormat
+                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float));
+
+  _v3n3t2 = register_format(new qpGeomVertexArrayFormat
+                            (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                             InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float,
+                             InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float));
+
+  // Define the DirectX-style packed color formats
+  _v3cp = register_format(new qpGeomVertexArrayFormat
+                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb));
+
+  _v3n3cp = register_format(new qpGeomVertexArrayFormat
+                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb));
+
+  _v3cpt2 = register_format(new qpGeomVertexArrayFormat
+                            (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                             InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb,
+                             InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float));
+
+  _v3n3cpt2 = register_format(new qpGeomVertexArrayFormat
+                              (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                               InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float,
+                               InternalName::get_color(), 1, qpGeomVertexDataType::NT_packed_argb,
+                               InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float));
+
+  // 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_float,
+                           InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8));
+
+  _v3n3c4 = register_format(new qpGeomVertexArrayFormat
+                          (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float,
+                           InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8));
+
+  _v3c4t2 = register_format(new qpGeomVertexArrayFormat
+                            (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                             InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8,
+                             InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float));
+
+  _v3n3c4t2 = register_format(new qpGeomVertexArrayFormat
+                              (InternalName::get_vertex(), 3, qpGeomVertexDataType::NT_float,
+                               InternalName::get_normal(), 3, qpGeomVertexDataType::NT_float,
+                               InternalName::get_color(), 4, qpGeomVertexDataType::NT_uint8,
+                               InternalName::get_texcoord(), 2, qpGeomVertexDataType::NT_float));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Registry::register_format
+//       Access: Public
+//  Description: Adds the indicated format to the registry, if there
+//               is not an equivalent format already there; in either
+//               case, returns the pointer to the equivalent format
+//               now in the registry.
+//
+//               This must be called before a format may be used in a
+//               Geom.  After this call, you should discard the
+//               original pointer you passed in (which may or may not
+//               now be invalid) and let its reference count decrement
+//               normally; you should use only the returned value from
+//               this point on.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) qpGeomVertexFormat::Registry::
+register_format(qpGeomVertexFormat *format) {
+  if (format->is_registered()) {
+    return format;
+  }
+
+  // Save the incoming pointer in a local PointerTo, so that if it has
+  // a zero reference count and is not added into the map below, it
+  // will be automatically deleted when this function returns.
+  PT(qpGeomVertexFormat) pt_format = format;
+
+  Formats::iterator fi = _formats.insert(format).first;
+
+  qpGeomVertexFormat *new_format = (*fi);
+  if (!new_format->is_registered()) {
+    new_format->do_register();
+  }
+
+  return new_format;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexFormat::Registry::unregister_format
+//       Access: Public
+//  Description: Removes the indicated format from the registry.
+//               Normally this should not be done until the format is
+//               destructing.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexFormat::Registry::
+unregister_format(qpGeomVertexFormat *format) {
+  nassertv(format->is_registered());
+  Formats::iterator fi = _formats.find(format);
+  nassertv(fi != _formats.end());
+  _formats.erase(fi);
+  format->do_unregister();
+}

+ 211 - 0
panda/src/gobj/qpgeomVertexFormat.h

@@ -0,0 +1,211 @@
+// Filename: qpgeomVertexFormat.h
+// Created by:  drose (07Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMVERTEXFORMAT_H
+#define qpGEOMVERTEXFORMAT_H
+
+#include "pandabase.h"
+#include "typedWritableReferenceCount.h"
+#include "qpgeomVertexArrayFormat.h"
+#include "internalName.h"
+#include "luse.h"
+#include "pointerTo.h"
+#include "pmap.h"
+#include "pset.h"
+#include "pvector.h"
+#include "pta_float.h"
+#include "indirectCompareTo.h"
+
+class FactoryParams;
+class qpGeomVertexData;
+class qpGeomMunger;
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomVertexFormat
+// Description : This class defines the layout of the vertex data
+//               arrays stored within a Geom.  The data within a Geom
+//               is typically stored within a single interleaved
+//               array, but it may also be distributed among multiple
+//               different arrays.  Each array is described by a
+//               qpGeomVertexArrayFormat object, referenced within
+//               this object.
+//
+//               There are a number of standard pre-defined
+//               GeomVertexFormat objects, or you may define your own
+//               as needed.  You may also record any combination of
+//               standard and/or user-defined data types in your
+//               custom GeomVertexFormat constructions.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomVertexFormat : public TypedWritableReferenceCount {
+PUBLISHED:
+  qpGeomVertexFormat();
+  qpGeomVertexFormat(qpGeomVertexArrayFormat *array_format);
+  qpGeomVertexFormat(const qpGeomVertexFormat &copy);
+  void operator = (const qpGeomVertexFormat &copy);
+  virtual ~qpGeomVertexFormat();
+
+  INLINE bool is_registered() const;
+  INLINE static CPT(qpGeomVertexFormat) register_format(qpGeomVertexFormat *format);
+  INLINE static CPT(qpGeomVertexFormat) register_format(qpGeomVertexArrayFormat *format);
+
+  INLINE int get_num_arrays() const;
+  INLINE const qpGeomVertexArrayFormat *get_array(int array) const;
+  qpGeomVertexArrayFormat *modify_array(int array);
+  void set_array(int array, qpGeomVertexArrayFormat *format);
+  void remove_array(int array);
+  void add_array(qpGeomVertexArrayFormat *array_format);
+  void clear_arrays();
+
+  int get_num_data_types() const;
+  int get_array_with(int i) const;
+  const qpGeomVertexDataType *get_data_type(int i) const;
+
+  int get_array_with(const InternalName *name) const;
+  const qpGeomVertexDataType *get_data_type(const InternalName *name) const;
+
+  void output(ostream &out) const;
+  void write(ostream &out, int indent_level = 0) const;
+  void write_with_data(ostream &out, int indent_level, 
+                       const qpGeomVertexData *data) const;
+
+  // Some standard vertex formats.  No particular requirement to use
+  // one of these, but the DirectX renderers can use these formats
+  // directly, whereas any other format will have to be converted
+  // first.
+  INLINE static const qpGeomVertexFormat *get_v3();
+  INLINE static const qpGeomVertexFormat *get_v3n3();
+  INLINE static const qpGeomVertexFormat *get_v3t2();
+  INLINE static const qpGeomVertexFormat *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).
+  INLINE static const qpGeomVertexFormat *get_v3cp();
+  INLINE static const qpGeomVertexFormat *get_v3cpt2();
+  INLINE static const qpGeomVertexFormat *get_v3n3cp();
+  INLINE static const qpGeomVertexFormat *get_v3n3cpt2();
+
+  // These formats, with an OpenGL-style four-byte color, are not
+  // supported directly by DirectX.  If you use them, the
+  // DXGraphicsStateGuardian will automatically convert to DirectX
+  // form (with a larger runtime overhead, since DirectX8, and old
+  // DirectX9 drivers, require everything to be interleaved together).
+  INLINE static const qpGeomVertexFormat *get_v3c4();
+  INLINE static const qpGeomVertexFormat *get_v3c4t2();
+  INLINE static const qpGeomVertexFormat *get_v3n3c4();
+  INLINE static const qpGeomVertexFormat *get_v3n3c4t2();
+
+public:
+  bool get_array_info(const InternalName *name,
+                      int &array_index,
+                      const qpGeomVertexDataType *&data_type) const;
+
+  int compare_to(const qpGeomVertexFormat &other) const;
+
+private:
+  class Registry;
+  INLINE static Registry *get_registry();
+  static void make_registry();
+
+  void do_register();
+  void do_unregister();
+
+  bool _is_registered;
+
+  typedef pvector< PT(qpGeomVertexArrayFormat) > Arrays;
+  Arrays _arrays;
+
+  class DataTypeRecord {
+  public:
+    int _array_index;
+    int _data_type_index;
+  };
+
+  typedef pmap<const InternalName *, DataTypeRecord> DataTypesByName;
+  DataTypesByName _data_types_by_name;
+
+  typedef pset<qpGeomMunger *> Mungers;
+  Mungers _mungers;
+
+  typedef pset<qpGeomVertexFormat *, IndirectCompareTo<qpGeomVertexFormat> > Formats;
+  class Registry {
+  public:
+    Registry();
+    CPT(qpGeomVertexFormat) register_format(qpGeomVertexFormat *format);
+    INLINE CPT(qpGeomVertexFormat) register_format(qpGeomVertexArrayFormat *format);
+    void unregister_format(qpGeomVertexFormat *format);
+
+    Formats _formats;
+
+    CPT(qpGeomVertexFormat) _v3;
+    CPT(qpGeomVertexFormat) _v3n3;
+    CPT(qpGeomVertexFormat) _v3t2;
+    CPT(qpGeomVertexFormat) _v3n3t2;
+    
+    CPT(qpGeomVertexFormat) _v3cp;
+    CPT(qpGeomVertexFormat) _v3n3cp;
+    CPT(qpGeomVertexFormat) _v3cpt2;
+    CPT(qpGeomVertexFormat) _v3n3cpt2;
+    
+    CPT(qpGeomVertexFormat) _v3c4;
+    CPT(qpGeomVertexFormat) _v3n3c4;
+    CPT(qpGeomVertexFormat) _v3c4t2;
+    CPT(qpGeomVertexFormat) _v3n3c4t2;
+  };
+
+  static Registry *_registry;
+
+
+public:
+  static void register_with_read_factory();
+  virtual void write_datagram(BamWriter *manager, Datagram &dg);
+  virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
+
+protected:
+  static TypedWritable *make_from_bam(const FactoryParams &params);
+  void fillin(DatagramIterator &scan, BamReader *manager);
+
+public:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    TypedWritableReferenceCount::init_type();
+    register_type(_type_handle, "qpGeomVertexFormat",
+                  TypedWritableReferenceCount::get_class_type());
+  }
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+
+private:
+  static TypeHandle _type_handle;
+
+  friend class qpGeomVertexFormat::Registry;
+  friend class qpGeomMunger;
+};
+
+INLINE ostream &operator << (ostream &out, const qpGeomVertexFormat &obj);
+
+#include "qpgeomVertexFormat.I"
+
+#endif

+ 380 - 0
panda/src/gobj/qpgeomVertexIterator.I

@@ -0,0 +1,380 @@
+// Filename: qpgeomVertexIterator.I
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomVertexIterator::Constructor
+//       Access: Published
+//  Description: Constructs a new iterator to process the vertices of
+//               the indicated data object.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexIterator::
+qpGeomVertexIterator(qpGeomVertexData *data) :
+  _data(data),
+  _array(0),
+  _data_type(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _write_vertex(0)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::Constructor
+//       Access: Published
+//  Description: Constructs a new iterator to process the vertices of
+//               the indicated data object.  This flavor creates the
+//               iterator specifically to process the named data type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexIterator::
+qpGeomVertexIterator(qpGeomVertexData *data, const string &name) :
+  _data(data),
+  _array(0),
+  _data_type(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _write_vertex(0)
+{
+  set_data_type(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::Constructor
+//       Access: Published
+//  Description: Constructs a new iterator to process the vertices of
+//               the indicated data object.  This flavor creates the
+//               iterator specifically to process the named data type.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexIterator::
+qpGeomVertexIterator(qpGeomVertexData *data, const InternalName *name) :
+  _data(data),
+  _array(0),
+  _data_type(NULL),
+  _start_vertex(0),
+  _read_vertex(0),
+  _write_vertex(0)
+{
+  set_data_type(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_data
+//       Access: Published
+//  Description: Returns the current data object that the iterator is
+//               processing.
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomVertexData *qpGeomVertexIterator::
+get_data() const {
+  return _data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data_type
+//       Access: Published
+//  Description: Sets up the iterator to use the nth data type of the
+//               GeomVertexFormat, numbering from 0.
+//
+//               This also resets the read and write 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.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data_type(int data_type) {
+  nassertv(_data->get_format()->get_array_with(data_type) >= 0);
+  set_data_type(_data->get_format()->get_array_with(data_type),
+                _data->get_format()->get_data_type(data_type));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data_type
+//       Access: Published
+//  Description: Sets up the iterator to use the data type with the
+//               indicated name.
+//
+//               This also resets the read and write 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.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data_type(const string &name) {
+  set_data_type(InternalName::make(name));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data_type
+//       Access: Published
+//  Description: Sets up the iterator to use the data type with the
+//               indicated name.
+//
+//               This also resets the read and write 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.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data_type(const InternalName *name) {
+  nassertv(_data->get_format()->get_array_with(name) >= 0);
+  set_data_type(_data->get_format()->get_array_with(name),
+                _data->get_format()->get_data_type(name));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data_type
+//       Access: Published
+//  Description: Sets up the iterator to use the indicated data_type
+//               description on the given array.
+//
+//               This also resets the read and write 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.)
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data_type(int array, const qpGeomVertexDataType *data_type) {
+  nassertv(array >= 0 && array < _data->get_num_arrays());
+  nassertv(data_type != (qpGeomVertexDataType *)NULL);
+  _array = array;
+  _data_type = data_type;
+
+  _read_vertex = _start_vertex;
+  _write_vertex = _start_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_array
+//       Access: Published
+//  Description: Returns the array index containing the data type that
+//               the iterator is working on.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexIterator::
+get_array() const {
+  return _array;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_data_type
+//       Access: Published
+//  Description: Returns the description of the data type that the
+//               iterator is working on.
+////////////////////////////////////////////////////////////////////
+INLINE const qpGeomVertexDataType *qpGeomVertexIterator::
+get_data_type() const {
+  return _data_type;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_vertex
+//       Access: Published
+//  Description: Sets the start, read, and write index to the
+//               indicated value.  The iterator will begin traversing
+//               from the given vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_vertex(int vertex) {
+  _start_vertex = vertex;
+  _read_vertex = vertex;
+  _write_vertex = vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_start_vertex
+//       Access: Published
+//  Description: Returns the vertex index at which the iterator
+//               started.  It will return to this vertex if you reset
+//               the current data_type.
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexIterator::
+get_start_vertex() const {
+  return _start_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_read_vertex
+//       Access: Published
+//  Description: Returns the current read vertex index of the
+//               iterator.  This is the index whose value will be
+//               returned by the next call to get_vertex().
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexIterator::
+get_read_vertex() const {
+  return _read_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_write_vertex
+//       Access: Published
+//  Description: Returns the current write vertex index of the
+//               iterator.  This is the index whose value will be
+//               modified by the next call to set_vertex().
+////////////////////////////////////////////////////////////////////
+INLINE int qpGeomVertexIterator::
+get_write_vertex() const {
+  return _write_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data1
+//       Access: Published
+//  Description: Sets the write vertex to a particular 1-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data1(float data) {
+  _data->set_data(_array, _data_type, _write_vertex, &data, 1);
+  ++_write_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data2
+//       Access: Published
+//  Description: Sets the write vertex to a particular 2-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data2(float x, float y) {
+  set_data2(LVecBase2f(x, y));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data2
+//       Access: Published
+//  Description: Sets the write vertex to a particular 2-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data2(const LVecBase2f &data) {
+  _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 2);
+  ++_write_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data3
+//       Access: Published
+//  Description: Sets the write vertex to a particular 3-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data3(float x, float y, float z) {
+  set_data3(LVecBase3f(x, y, z));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data3
+//       Access: Published
+//  Description: Sets the write vertex to a particular 3-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data3(const LVecBase3f &data) {
+  _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 3);
+  ++_write_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data4
+//       Access: Published
+//  Description: Sets the write vertex to a particular 4-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data4(float x, float y, float z, float w) {
+  set_data4(LVecBase4f(x, y, z, w));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::set_data4
+//       Access: Published
+//  Description: Sets the write vertex to a particular 4-component
+//               value, and advances the write vertex.
+////////////////////////////////////////////////////////////////////
+INLINE void qpGeomVertexIterator::
+set_data4(const LVecBase4f &data) {
+  _data->set_data(_array, _data_type, _write_vertex, data.get_data(), 4);
+  ++_write_vertex;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_data1
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 1-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE float qpGeomVertexIterator::
+get_data1() {
+  float data;
+  _data->get_data(_array, _data_type, _read_vertex, &data, 1);
+  ++_read_vertex;
+  return data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_data2
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 2-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase2f qpGeomVertexIterator::
+get_data2() {
+  float data[4];
+  int num_values = min(_data_type->get_num_values(), 4);
+  _data->get_data(_array, _data_type, _read_vertex, data, num_values);
+  ++_read_vertex;
+  LVecBase2f result;
+  qpGeomVertexData::to_vec2(result, data, num_values);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_data3
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 3-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase3f qpGeomVertexIterator::
+get_data3() {
+  float data[4];
+  int num_values = min(_data_type->get_num_values(), 4);
+  _data->get_data(_array, _data_type, _read_vertex, data, num_values);
+  ++_read_vertex;
+  LVecBase3f result;
+  qpGeomVertexData::to_vec3(result, data, num_values);
+  return result;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexIterator::get_data4
+//       Access: Published
+//  Description: Returns the data associated with the read vertex,
+//               expressed as a 4-component value, and advances the
+//               read vertex.
+////////////////////////////////////////////////////////////////////
+INLINE LVecBase4f qpGeomVertexIterator::
+get_data4() {
+  float data[4];
+  int num_values = min(_data_type->get_num_values(), 4);
+  _data->get_data(_array, _data_type, _read_vertex, data, num_values);
+  ++_read_vertex;
+  LVecBase4f result;
+  qpGeomVertexData::to_vec4(result, data, num_values);
+  return result;
+}

+ 19 - 0
panda/src/gobj/qpgeomVertexIterator.cxx

@@ -0,0 +1,19 @@
+// Filename: qpgeomVertexIterator.cxx
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "qpgeomVertexIterator.h"

+ 86 - 0
panda/src/gobj/qpgeomVertexIterator.h

@@ -0,0 +1,86 @@
+// Filename: qpgeomVertexIterator.h
+// Created by:  drose (10Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMVERTEXITERATOR_H
+#define qpGEOMVERTEXITERATOR_H
+
+#include "pandabase.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomVertexDataType.h"
+#include "internalName.h"
+#include "luse.h"
+#include "pointerTo.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomVertexIterator
+// Description : This is used to read or write the vertices of a
+//               GeomVertexData structure, one vertex and data type at
+//               a time.
+//
+//               This is part of the experimental Geom rewrite.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomVertexIterator {
+PUBLISHED:
+  INLINE qpGeomVertexIterator(qpGeomVertexData *data);
+  INLINE qpGeomVertexIterator(qpGeomVertexData *data,
+                              const string &name);
+  INLINE qpGeomVertexIterator(qpGeomVertexData *data,
+                              const InternalName *name);
+
+  INLINE qpGeomVertexData *get_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);
+  INLINE 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 int get_write_vertex() const;
+
+  INLINE void set_data1(float data);
+  INLINE void set_data2(float x, float y);
+  INLINE void set_data2(const LVecBase2f &data);
+  INLINE void set_data3(float x, float y, float z);
+  INLINE void set_data3(const LVecBase3f &data);
+  INLINE void set_data4(float x, float y, float z, float w);
+  INLINE void set_data4(const LVecBase4f &data);
+
+  INLINE float get_data1();
+  INLINE LVecBase2f get_data2();
+  INLINE LVecBase3f get_data3();
+  INLINE LVecBase4f get_data4();
+
+private:
+  PT(qpGeomVertexData) _data;
+  int _array;
+  const qpGeomVertexDataType *_data_type;
+
+  int _start_vertex;
+  int _read_vertex;
+  int _write_vertex;
+};
+
+#include "qpgeomVertexIterator.I"
+
+#endif

+ 0 - 49
panda/src/gobj/texCoordName.I

@@ -1,49 +0,0 @@
-// Filename: texCoordName.I
-// Created by:  masad (15Jul04)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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: TexCoordName::get_name
-//       Access: Published
-//  Description: Return the name string of this texcoordname
-////////////////////////////////////////////////////////////////////
-INLINE const string &TexCoordName::
-get_name() const {
-  return _name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::get_default
-//       Access: Published, Static
-//  Description: Returns the default TexCoordName that will be used
-//               for all geometry that does not give a particular name
-//               for its UV's
-////////////////////////////////////////////////////////////////////
-INLINE const TexCoordName *TexCoordName::
-get_default() {
-  if (_default_name == (TexCoordName *)NULL) {
-    _default_name = TexCoordName::make("default");
-  }
-  return _default_name;
-}
-
-INLINE ostream &
-operator << (ostream &out, const TexCoordName &tcn) {
-  tcn.output(out);
-  return out;
-}

+ 0 - 161
panda/src/gobj/texCoordName.cxx

@@ -1,161 +0,0 @@
-// Filename: texCoordName.cxx
-// Created by: masad (15Jul04)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "pandabase.h"
-#include "texCoordName.h"
-#include "datagram.h"
-#include "datagramIterator.h"
-#include "bamReader.h"
-#include "preparedGraphicsObjects.h"
-
-TexCoordName::TexCoordsByName TexCoordName::_texcoords_by_name;
-CPT(TexCoordName) TexCoordName::_default_name;
-
-TypeHandle TexCoordName::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::Constructor
-//       Access: Private
-//  Description: Use make() to make a new TexCoordName instance.
-////////////////////////////////////////////////////////////////////
-TexCoordName::
-TexCoordName(const string &name) {
-  _name = name;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::Destructor
-//       Access: Published, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-TexCoordName::
-~TexCoordName() {
-  TexCoordsByName::iterator ni = _texcoords_by_name.find(_name);
-  nassertv(ni != _texcoords_by_name.end());
-  _texcoords_by_name.erase(ni);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::make
-//       Access: Published
-//  Description: The public interface for constructing a TexCoordName
-//               pointer.  This will return a new TexCoordName
-//               associated with the indicated name, if this is the
-//               first time the particular name has been requested; if
-//               the name is already in use, it will return the
-//               existing pointer.
-////////////////////////////////////////////////////////////////////
-const TexCoordName *TexCoordName::
-make(const string &name) {
-  TexCoordsByName::iterator ni = _texcoords_by_name.find(name);
-  if (ni != _texcoords_by_name.end()) {
-    return (*ni).second;
-  }
-
-  TexCoordName *texcoord = new TexCoordName(name);
-  _texcoords_by_name[name] = texcoord;
-  return texcoord;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::output
-//       Access: Published
-//  Description: output the TexCoordName and its member data
-////////////////////////////////////////////////////////////////////
-void TexCoordName::
-output(ostream &out) const {
-  out << get_name();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::register_with_read_factory
-//       Access: Public, Static
-//  Description: Factory method to generate a TexCoordName object
-////////////////////////////////////////////////////////////////////
-void TexCoordName::
-register_with_read_factory() {
-  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::finalize
-//       Access: Public, Virtual
-//  Description: Method to ensure that any necessary clean up tasks
-//               that have to be performed by this object are performed
-////////////////////////////////////////////////////////////////////
-void TexCoordName::
-finalize() {
-  // Unref the pointer that we explicitly reffed in make_from_bam().
-  unref();
-
-  // We should never get back to zero after unreffing our own count,
-  // because we expect to have been stored in a pointer somewhere.  If
-  // we do get to zero, it's a memory leak; the way to avoid this is
-  // to call unref_delete() above instead of unref(), but this is
-  // dangerous to do from within a virtual function.
-  nassertv(get_ref_count() != 0);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::make_from_bam
-//       Access: Protected, Static
-//  Description: This function is called by the BamReader's factory
-//               when a new object of type TexCoordName is encountered
-//               in the Bam file.  It should create the TexCoordName
-//               and extract its information from the file.
-////////////////////////////////////////////////////////////////////
-TypedWritable *TexCoordName::
-make_from_bam(const FactoryParams &params) {
-  // The process of making a TexCoordName is slightly
-  // different than making other Writable objects.
-  // That is because all creation of TexCoordNames should
-  // be done through the make() constructor.
-  DatagramIterator scan;
-  BamReader *manager;
-
-  parse_params(params, scan, manager);
-
-  // The name is the only thing written to the data stream.
-  string name = scan.get_string();
-
-  // Make a new TexCoordName with that name (or get the previous one
-  // if there is one already).
-  PT(TexCoordName) me = (TexCoordName *)make(name);
-
-  // But now we have a problem, since we have to hold the reference
-  // count and there's no way to return a TypedWritable while still
-  // holding the reference count!  We work around this by explicitly
-  // upping the count, and also setting a finalize() callback to down
-  // it later.
-  me->ref();
-  manager->register_finalize(me);
-  
-  return me.p();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TexCoordName::write_datagram
-//       Access: Public
-//  Description: Function to write the important information in
-//               the particular object to a Datagram
-////////////////////////////////////////////////////////////////////
-void TexCoordName::
-write_datagram(BamWriter *manager, Datagram &me) {
-  me.add_string(_name);
-}
-

+ 0 - 92
panda/src/gobj/texCoordName.h

@@ -1,92 +0,0 @@
-// Filename: texCoordName.h
-// Created by:  drose (15Jul04)
-//
-////////////////////////////////////////////////////////////////////
-//
-// 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 TEXCOORDNAME_H
-#define TEXCOORDNAME_H
-
-#include "pandabase.h"
-
-#include "typedWritableReferenceCount.h"
-
-class FactoryParams;
-
-////////////////////////////////////////////////////////////////////
-//       Class : TexCoordName
-// Description : Associates a name with a set of texture coordinates,
-//               for the purpose of storing within a Geom.  This is
-//               used in conjunction with TextureStage to support
-//               multitexturing.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA TexCoordName : public TypedWritableReferenceCount {
-private:
-  TexCoordName(const string &name);
-
-PUBLISHED:
-  virtual ~TexCoordName();
-
-  static const TexCoordName *make(const string &name);
-  INLINE const string &get_name() const;
-
-  void output(ostream &out) const;
-
-  INLINE static const TexCoordName *get_default();
-
-private:
-  string _name;
-
-  typedef phash_map<string, TexCoordName *, string_hash> TexCoordsByName;
-  static TexCoordsByName _texcoords_by_name;
-
-  static CPT(TexCoordName) _default_name;
-  
-public:
-  // Datagram stuff
-  static void register_with_read_factory();
-  virtual void write_datagram(BamWriter *manager, Datagram &me);
-
-  virtual void finalize();
-
-protected:
-  static TypedWritable *make_from_bam(const FactoryParams &params);
-
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    TypedWritableReferenceCount::init_type();
-    register_type(_type_handle, "TexCoordName",
-                  TypedWritableReferenceCount::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-INLINE ostream &operator << (ostream &out, const TexCoordName &tcn);
-
-#include "texCoordName.I"
-
-#endif
-
-
-  

+ 4 - 4
panda/src/gobj/textureStage.I

@@ -136,7 +136,7 @@ operator < (const TextureStage &other) const {
 //               sets, each of which must have a unique name.
 //               sets, each of which must have a unique name.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TextureStage::
 INLINE void TextureStage::
-set_texcoord_name(const TexCoordName *name) {
+set_texcoord_name(const InternalName *name) {
   _texcoord_name = name;
   _texcoord_name = name;
 }
 }
 
 
@@ -149,15 +149,15 @@ set_texcoord_name(const TexCoordName *name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void TextureStage::
 INLINE void TextureStage::
 set_texcoord_name(const string &name) {
 set_texcoord_name(const string &name) {
-  _texcoord_name = TexCoordName::make(name);
+  _texcoord_name = InternalName::get_texcoord_name(name);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureStage::get_texcoord_name
 //     Function: TextureStage::get_texcoord_name
 //       Access: Published
 //       Access: Published
-//  Description: Returns the TexCoordName
+//  Description: Returns the InternalName
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const TexCoordName *TextureStage::
+INLINE const InternalName *TextureStage::
 get_texcoord_name() const {
 get_texcoord_name() const {
   return _texcoord_name;
   return _texcoord_name;
 }
 }

+ 3 - 3
panda/src/gobj/textureStage.cxx

@@ -17,7 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
 #include "textureStage.h"
 #include "textureStage.h"
-#include "texCoordName.h"
+#include "internalName.h"
 
 
 PT(TextureStage) TextureStage::_default_stage;
 PT(TextureStage) TextureStage::_default_stage;
 UpdateSeq TextureStage::_sort_seq;
 UpdateSeq TextureStage::_sort_seq;
@@ -34,7 +34,7 @@ TextureStage(const string &name) {
   _name = name;
   _name = name;
   _sort = 0;
   _sort = 0;
   _priority = 0;
   _priority = 0;
-  _texcoord_name = TexCoordName::get_default();
+  _texcoord_name = InternalName::get_texcoord();
   _mode = M_modulate;
   _mode = M_modulate;
   _color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _color.set(0.0f, 0.0f, 0.0f, 1.0f);
   _rgb_scale = 1;
   _rgb_scale = 1;
@@ -319,7 +319,7 @@ int TextureStage::
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
 complete_pointers(TypedWritable **p_list, BamReader *manager) {
   int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
   int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
 
 
-  _texcoord_name = DCAST(TexCoordName, p_list[pi++]);
+  _texcoord_name = DCAST(InternalName, p_list[pi++]);
 
 
   return pi;
   return pi;
 }
 }

+ 4 - 4
panda/src/gobj/textureStage.h

@@ -21,7 +21,7 @@
 
 
 #include "pandabase.h"
 #include "pandabase.h"
 
 
-#include "texCoordName.h"
+#include "internalName.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "typedWritableReferenceCount.h"
 #include "typedWritableReferenceCount.h"
 #include "updateSeq.h"
 #include "updateSeq.h"
@@ -100,9 +100,9 @@ PUBLISHED:
 
 
   INLINE bool operator < (const TextureStage &other) const;
   INLINE bool operator < (const TextureStage &other) const;
 
 
-  INLINE void set_texcoord_name(const TexCoordName *name);
+  INLINE void set_texcoord_name(const InternalName *name);
   INLINE void set_texcoord_name(const string &texcoord_name);
   INLINE void set_texcoord_name(const string &texcoord_name);
-  INLINE const TexCoordName *get_texcoord_name() const;
+  INLINE const InternalName *get_texcoord_name() const;
 
 
   INLINE void set_mode(Mode mode);
   INLINE void set_mode(Mode mode);
   INLINE Mode get_mode() const;
   INLINE Mode get_mode() const;
@@ -170,7 +170,7 @@ private:
   string _name;
   string _name;
   int _sort;
   int _sort;
   int _priority;
   int _priority;
-  CPT(TexCoordName) _texcoord_name;
+  CPT(InternalName) _texcoord_name;
   Mode _mode;
   Mode _mode;
   Colorf _color;
   Colorf _color;
   int _rgb_scale;
   int _rgb_scale;

+ 5 - 5
panda/src/grutil/multitexReducer.cxx

@@ -116,7 +116,7 @@ scan(PandaNode *node, const RenderState *state, const TransformState *transform)
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MultitexReducer::set_target
 //     Function: MultitexReducer::set_target
 //       Access: Published
 //       Access: Published
-//  Description: Specifies the target TextureStage (and TexCoordName)
+//  Description: Specifies the target TextureStage (and InternalName)
 //               that will be left on each multitexture node after the
 //               that will be left on each multitexture node after the
 //               flatten operation has completed.
 //               flatten operation has completed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -544,7 +544,7 @@ bool MultitexReducer::
 determine_uv_range(TexCoordf &min_uv, TexCoordf &max_uv,
 determine_uv_range(TexCoordf &min_uv, TexCoordf &max_uv,
                    const MultitexReducer::StageInfo &model_stage,
                    const MultitexReducer::StageInfo &model_stage,
                    const MultitexReducer::GeomList &geom_list) const {
                    const MultitexReducer::GeomList &geom_list) const {
-  const TexCoordName *model_name = model_stage._stage->get_texcoord_name();
+  const InternalName *model_name = model_stage._stage->get_texcoord_name();
   bool got_any = false;
   bool got_any = false;
 
 
   GeomList::const_iterator gi;
   GeomList::const_iterator gi;
@@ -799,7 +799,7 @@ make_texture_layer(const NodePath &render,
 //               coordinates to the target set.
 //               coordinates to the target set.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MultitexReducer::
 void MultitexReducer::
-transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
+transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
               const MultitexReducer::GeomList &geom_list,
               const MultitexReducer::GeomList &geom_list,
               bool preserve_color) {
               bool preserve_color) {
   GeomList::const_iterator gi;
   GeomList::const_iterator gi;
@@ -820,8 +820,8 @@ transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
       }
       }
       
       
       geom->set_coords(coords, geom->get_texcoords_index(_target_stage->get_texcoord_name()));
       geom->set_coords(coords, geom->get_texcoords_index(_target_stage->get_texcoord_name()));
-      if (texcoord_name != (const TexCoordName *)NULL) {
-        geom->set_texcoords(TexCoordName::get_default(),
+      if (texcoord_name != (const InternalName *)NULL) {
+        geom->set_texcoords(InternalName::get_texcoord(),
                             geom->get_texcoords_array(texcoord_name),
                             geom->get_texcoords_array(texcoord_name),
                             geom->get_texcoords_index(texcoord_name));
                             geom->get_texcoords_index(texcoord_name));
       }
       }

+ 1 - 1
panda/src/grutil/multitexReducer.h

@@ -139,7 +139,7 @@ private:
                           const StageInfo &stage_info, 
                           const StageInfo &stage_info, 
                           const GeomList &geom_list,
                           const GeomList &geom_list,
                           bool force_use_geom);
                           bool force_use_geom);
-  void transfer_geom(GeomNode *geom_node, const TexCoordName *texcoord_name,
+  void transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
                      const GeomList &geom_list, bool preserve_color);
                      const GeomList &geom_list, bool preserve_color);
 
 
   void scan_color(const GeomList &geom_list, Colorf &geom_color, 
   void scan_color(const GeomList &geom_list, Colorf &geom_color, 

+ 10 - 0
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -43,6 +43,10 @@ class GeomTri;
 class GeomTristrip;
 class GeomTristrip;
 class GeomTrifan;
 class GeomTrifan;
 class GeomSphere;
 class GeomSphere;
+class qpGeomVertexData;
+class qpGeomTriangles;
+class qpGeomTristrips;
+class qpGeomTrifans;
 
 
 class PreparedGraphicsObjects;
 class PreparedGraphicsObjects;
 class GraphicsOutput;
 class GraphicsOutput;
@@ -165,6 +169,12 @@ public:
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc)=0;
   virtual void draw_trifan(GeomTrifan *geom, GeomContext *gc)=0;
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0;
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc)=0;
 
 
+  virtual void begin_draw_primitives(const qpGeomVertexData *vertex_data)=0;
+  virtual void draw_triangles(qpGeomTriangles *primitive)=0;
+  virtual void draw_tristrips(qpGeomTristrips *primitive)=0;
+  virtual void draw_trifans(qpGeomTrifans *primitive)=0;
+  virtual void end_draw_primitives()=0;
+
   virtual void framebuffer_copy_to_texture
   virtual void framebuffer_copy_to_texture
   (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
   (Texture *tex, int z, const DisplayRegion *dr, const RenderBuffer &rb)=0;
   virtual bool framebuffer_copy_to_ram
   virtual bool framebuffer_copy_to_ram

+ 4 - 4
panda/src/pgraph/geomNode.I

@@ -182,10 +182,10 @@ get_default_collide_mask() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomNode::count_name
 //     Function: GeomNode::count_name
 //       Access: Private
 //       Access: Private
-//  Description: Increments the count for the indicated TexCoordName.
+//  Description: Increments the count for the indicated InternalName.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void GeomNode::
 INLINE void GeomNode::
-count_name(GeomNode::NameCount &name_count, const TexCoordName *name) {
+count_name(GeomNode::NameCount &name_count, const InternalName *name) {
   pair<NameCount::iterator, bool> result = 
   pair<NameCount::iterator, bool> result = 
     name_count.insert(NameCount::value_type(name, 1));
     name_count.insert(NameCount::value_type(name, 1));
   if (!result.second) {
   if (!result.second) {
@@ -196,10 +196,10 @@ count_name(GeomNode::NameCount &name_count, const TexCoordName *name) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomNode::get_name_count
 //     Function: GeomNode::get_name_count
 //       Access: Private
 //       Access: Private
-//  Description: Returns the count for the indicated TexCoordName.
+//  Description: Returns the count for the indicated InternalName.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int GeomNode::
 INLINE int GeomNode::
-get_name_count(const GeomNode::NameCount &name_count, const TexCoordName *name) {
+get_name_count(const GeomNode::NameCount &name_count, const InternalName *name) {
   NameCount::const_iterator ni;
   NameCount::const_iterator ni;
   ni = name_count.find(name);
   ni = name_count.find(name);
   if (ni != name_count.end()) {
   if (ni != name_count.end()) {

+ 2 - 2
panda/src/pgraph/geomNode.cxx

@@ -235,7 +235,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
           int num_on_stages = ta->get_num_on_stages();
           int num_on_stages = ta->get_num_on_stages();
           for (int si = 0; si < num_on_stages; si++) {
           for (int si = 0; si < num_on_stages; si++) {
             TextureStage *stage = ta->get_on_stage(si);
             TextureStage *stage = ta->get_on_stage(si);
-            const TexCoordName *name = stage->get_texcoord_name();
+            const InternalName *name = stage->get_texcoord_name();
             count_name(name_count, name);
             count_name(name_count, name);
           }
           }
         }
         }
@@ -248,7 +248,7 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
         int num_stages = tma->get_num_stages();
         int num_stages = tma->get_num_stages();
         for (int i = 0; i < num_stages; i++) {
         for (int i = 0; i < num_stages; i++) {
           TextureStage *stage = tma->get_stage(i);
           TextureStage *stage = tma->get_stage(i);
-          const TexCoordName *name = stage->get_texcoord_name();
+          const InternalName *name = stage->get_texcoord_name();
           if (get_name_count(name_count, name) > 1) {
           if (get_name_count(name_count, name) > 1) {
             // We can't transform these texcoords, since the name is
             // We can't transform these texcoords, since the name is
             // used by more than one active stage.
             // used by more than one active stage.

+ 3 - 3
panda/src/pgraph/geomNode.h

@@ -92,10 +92,10 @@ public:
 
 
 private:
 private:
   typedef pvector<GeomEntry> Geoms;
   typedef pvector<GeomEntry> Geoms;
-  typedef pmap<const TexCoordName *, int> NameCount;
+  typedef pmap<const InternalName *, int> NameCount;
 
 
-  INLINE void count_name(NameCount &name_count, const TexCoordName *name);
-  INLINE int get_name_count(const NameCount &name_count, const TexCoordName *name);
+  INLINE void count_name(NameCount &name_count, const InternalName *name);
+  INLINE int get_name_count(const NameCount &name_count, const InternalName *name);
 
 
   // This is the data that must be cycled between pipeline stages.
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
   class EXPCL_PANDA CData : public CycleData {

+ 4 - 4
panda/src/pgraph/geomTransformer.cxx

@@ -150,8 +150,8 @@ transform_vertices(GeomNode *node, const LMatrix4f &mat) {
 //               Geom was changed, false otherwise.
 //               Geom was changed, false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomTransformer::
 bool GeomTransformer::
-transform_texcoords(Geom *geom, const TexCoordName *from_name, 
-                    const TexCoordName *to_name, const LMatrix4f &mat) {
+transform_texcoords(Geom *geom, const InternalName *from_name, 
+                    const InternalName *to_name, const LMatrix4f &mat) {
   bool transformed = false;
   bool transformed = false;
 
 
   nassertr(geom != (Geom *)NULL, false);
   nassertr(geom != (Geom *)NULL, false);
@@ -201,8 +201,8 @@ transform_texcoords(Geom *geom, const TexCoordName *from_name,
 //               false otherwise.
 //               false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool GeomTransformer::
 bool GeomTransformer::
-transform_texcoords(GeomNode *node, const TexCoordName *from_name,
-                    const TexCoordName *to_name, const LMatrix4f &mat) {
+transform_texcoords(GeomNode *node, const InternalName *from_name,
+                    const InternalName *to_name, const LMatrix4f &mat) {
   bool any_changed = false;
   bool any_changed = false;
 
 
   GeomNode::CDWriter cdata(node->_cycler);
   GeomNode::CDWriter cdata(node->_cycler);

+ 5 - 5
panda/src/pgraph/geomTransformer.h

@@ -26,7 +26,7 @@
 
 
 class GeomNode;
 class GeomNode;
 class RenderState;
 class RenderState;
-class TexCoordName;
+class InternalName;
 
 
 ///////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////
 //       Class : GeomTransformer
 //       Class : GeomTransformer
@@ -52,11 +52,11 @@ public:
   bool transform_vertices(Geom *geom, const LMatrix4f &mat);
   bool transform_vertices(Geom *geom, const LMatrix4f &mat);
   bool transform_vertices(GeomNode *node, const LMatrix4f &mat);
   bool transform_vertices(GeomNode *node, const LMatrix4f &mat);
 
 
-  bool transform_texcoords(Geom *geom, const TexCoordName *from_name,
-                           const TexCoordName *to_name,
+  bool transform_texcoords(Geom *geom, const InternalName *from_name,
+                           const InternalName *to_name,
                            const LMatrix4f &mat);
                            const LMatrix4f &mat);
-  bool transform_texcoords(GeomNode *node, const TexCoordName *from_name,
-                           const TexCoordName *to_name,
+  bool transform_texcoords(GeomNode *node, const InternalName *from_name,
+                           const InternalName *to_name,
                            const LMatrix4f &mat);
                            const LMatrix4f &mat);
 
 
   bool set_color(Geom *geom, const Colorf &color);
   bool set_color(Geom *geom, const Colorf &color);