Browse Source

use_qpgeom for TextNode, CollisionSolid

David Rose 21 years ago
parent
commit
2aad0846b9
46 changed files with 1394 additions and 439 deletions
  1. 54 22
      panda/src/collide/collisionInvSphere.cxx
  2. 55 24
      panda/src/collide/collisionLine.cxx
  3. 52 13
      panda/src/collide/collisionPlane.cxx
  4. 56 16
      panda/src/collide/collisionPolygon.cxx
  5. 51 20
      panda/src/collide/collisionRay.cxx
  6. 38 14
      panda/src/collide/collisionSegment.cxx
  7. 56 23
      panda/src/collide/collisionSphere.cxx
  8. 93 37
      panda/src/collide/collisionTube.cxx
  9. 1 1
      panda/src/framework/windowFramework.cxx
  10. 1 1
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  11. 10 0
      panda/src/gobj/config_gobj.cxx
  12. 1 0
      panda/src/gobj/config_gobj.h
  13. 4 1
      panda/src/gobj/geom.cxx
  14. 1 1
      panda/src/gobj/geom.h
  15. 38 0
      panda/src/gobj/qpgeom.cxx
  16. 2 0
      panda/src/gobj/qpgeom.h
  17. 30 1
      panda/src/gobj/qpgeomPrimitive.cxx
  18. 1 0
      panda/src/gobj/qpgeomPrimitive.h
  19. 20 8
      panda/src/gobj/qpgeomVertexArrayData.I
  20. 44 40
      panda/src/gobj/qpgeomVertexArrayData.cxx
  21. 12 5
      panda/src/gobj/qpgeomVertexArrayData.h
  22. 11 1
      panda/src/gobj/qpgeomVertexData.I
  23. 51 1
      panda/src/gobj/qpgeomVertexData.cxx
  24. 6 0
      panda/src/gobj/qpgeomVertexData.h
  25. 2 2
      panda/src/gobj/qpgeomVertexReader.I
  26. 7 0
      panda/src/gobj/qpgeomVertexReader.cxx
  27. 6 0
      panda/src/gobj/qpgeomVertexReader.h
  28. 2 2
      panda/src/gobj/qpgeomVertexWriter.I
  29. 7 0
      panda/src/gobj/qpgeomVertexWriter.cxx
  30. 6 0
      panda/src/gobj/qpgeomVertexWriter.h
  31. 1 1
      panda/src/pgraph/cullableObject.cxx
  32. 1 1
      panda/src/pgraph/geomNode.cxx
  33. 4 4
      panda/src/pgraph/geomTransformer.cxx
  34. 6 6
      panda/src/pgraph/geomTransformer.h
  35. 3 0
      panda/src/text/Sources.pp
  36. 4 0
      panda/src/text/config_text.cxx
  37. 78 33
      panda/src/text/dynamicTextGlyph.cxx
  38. 47 0
      panda/src/text/qpgeomTextGlyph.I
  39. 101 0
      panda/src/text/qpgeomTextGlyph.cxx
  40. 77 0
      panda/src/text/qpgeomTextGlyph.h
  41. 57 17
      panda/src/text/staticTextFont.cxx
  42. 5 3
      panda/src/text/staticTextFont.h
  43. 2 0
      panda/src/text/textNode.I
  44. 288 140
      panda/src/text/textNode.cxx
  45. 1 1
      panda/src/text/textProperties.cxx
  46. 1 0
      panda/src/text/text_composite1.cxx

+ 54 - 22
panda/src/collide/collisionInvSphere.cxx

@@ -24,7 +24,6 @@
 #include "collisionHandler.h"
 #include "collisionEntry.h"
 #include "config_collide.h"
-
 #include "omniBoundingVolume.h"
 #include "datagram.h"
 #include "datagramIterator.h"
@@ -32,6 +31,9 @@
 #include "bamWriter.h"
 #include "geomTristrip.h"
 #include "nearly_zero.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionInvSphere::_type_handle;
 
@@ -306,31 +308,61 @@ fill_viz_geom() {
   static const int num_slices = 16;
   static const int num_stacks = 8;
 
-  GeomTristrip *sphere = new GeomTristrip;
-  PTA_Vertexf verts;
-  PTA_int lengths;
-  verts.reserve((num_stacks * 2) * num_slices);
-  lengths.reserve(num_slices);
-
-  for (int sl = 0; sl < num_slices; sl++) {
-    float longitude0 = (float)sl / (float)num_slices;
-    float longitude1 = (float)(sl + 1) / (float)num_slices;
-    verts.push_back(compute_point(0.0, longitude0));
-    for (int st = 1; st < num_stacks; st++) {
-      float latitude = (float)st / (float)num_stacks;
-      verts.push_back(compute_point(latitude, longitude1));
-      verts.push_back(compute_point(latitude, longitude0));
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    for (int sl = 0; sl < num_slices; ++sl) {
+      float longitude0 = (float)sl / (float)num_slices;
+      float longitude1 = (float)(sl + 1) / (float)num_slices;
+      vertex.add_data3f(compute_point(0.0, longitude0));
+      for (int st = 1; st < num_stacks; ++st) {
+        float latitude = (float)st / (float)num_stacks;
+        vertex.add_data3f(compute_point(latitude, longitude1));
+        vertex.add_data3f(compute_point(latitude, longitude0));
+      }
+      vertex.add_data3f(compute_point(1.0, longitude0));
+
+      strip->add_next_vertices(num_stacks * 2);
+      strip->close_primitive();
     }
-    verts.push_back(compute_point(1.0, longitude0));
 
-    lengths.push_back(num_stacks * 2);
-  }
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    _viz_geom->add_geom(geom, get_solid_viz_state());
 
-  sphere->set_coords(verts);
-  sphere->set_lengths(lengths);
-  sphere->set_num_prims(num_slices);
+  } else {
+    GeomTristrip *sphere = new GeomTristrip;
+    PTA_Vertexf verts;
+    PTA_int lengths;
+    verts.reserve((num_stacks * 2) * num_slices);
+    lengths.reserve(num_slices);
+    
+    for (int sl = 0; sl < num_slices; sl++) {
+      float longitude0 = (float)sl / (float)num_slices;
+      float longitude1 = (float)(sl + 1) / (float)num_slices;
+      verts.push_back(compute_point(0.0, longitude0));
+      for (int st = 1; st < num_stacks; st++) {
+        float latitude = (float)st / (float)num_stacks;
+        verts.push_back(compute_point(latitude, longitude1));
+        verts.push_back(compute_point(latitude, longitude0));
+      }
+      verts.push_back(compute_point(1.0, longitude0));
+      
+      lengths.push_back(num_stacks * 2);
+    }
+    
+    sphere->set_coords(verts);
+    sphere->set_lengths(lengths);
+    sphere->set_num_prims(num_slices);
 
-  _viz_geom->add_geom(sphere, get_solid_viz_state());
+    _viz_geom->add_geom(sphere, get_solid_viz_state());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 55 - 24
panda/src/collide/collisionLine.cxx

@@ -30,6 +30,9 @@
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamWriter.h"
+#include "qpgeom.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionLine::_type_handle;
 
@@ -77,34 +80,62 @@ fill_viz_geom() {
       << "Recomputing viz for " << *this << "\n";
   }
 
-  GeomLinestrip *line = new GeomLinestrip;
-  PTA_Vertexf verts;
-  PTA_Colorf colors;
-  PTA_int lengths;
-
   static const int num_points = 100;
   static const double scale = 100.0;
 
-  verts.reserve(num_points);
-  colors.reserve(num_points);
-
-  for (int i = 0; i < num_points; i++) {
-    double t = ((double)i / (double)num_points - 0.5) * 2.0;
-    verts.push_back(get_origin() + t * scale * get_direction());
-
-    colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f) +
-                     fabs(t) * Colorf(0.0f, 0.0f, 0.0f, -1.0f));
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+    
+    for (int i = 0; i < num_points; i++) {
+      double t = ((double)i / (double)num_points - 0.5) * 2.0;
+      vertex.add_data3f(get_origin() + t * scale * get_direction());
+      
+      color.add_data4f(Colorf(1.0f, 1.0f, 1.0f, 1.0f) +
+                       fabs(t) * Colorf(0.0f, 0.0f, 0.0f, -1.0f));
+    }
+
+    PT(qpGeomLinestrips) line = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+    line->add_next_vertices(num_points);
+    line->close_primitive();
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(line);
+
+    _viz_geom->add_geom(geom, get_other_viz_state());
+    _bounds_viz_geom->add_geom(geom, get_other_bounds_viz_state());
+
+  } else {
+    GeomLinestrip *line = new GeomLinestrip;
+    PTA_Vertexf verts;
+    PTA_Colorf colors;
+    PTA_int lengths;
+    
+    verts.reserve(num_points);
+    colors.reserve(num_points);
+    
+    for (int i = 0; i < num_points; i++) {
+      double t = ((double)i / (double)num_points - 0.5) * 2.0;
+      verts.push_back(get_origin() + t * scale * get_direction());
+      
+      colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f) +
+                       fabs(t) * Colorf(0.0f, 0.0f, 0.0f, -1.0f));
+    }
+    line->set_coords(verts);
+    line->set_colors(colors, G_PER_VERTEX);
+    
+    lengths.push_back(num_points-1);
+    line->set_lengths(lengths);
+    
+    line->set_num_prims(1);
+    
+    _viz_geom->add_geom(line, get_other_viz_state());
+    _bounds_viz_geom->add_geom(line, get_other_bounds_viz_state());
   }
-  line->set_coords(verts);
-  line->set_colors(colors, G_PER_VERTEX);
-
-  lengths.push_back(num_points-1);
-  line->set_lengths(lengths);
-
-  line->set_num_prims(1);
-
-  _viz_geom->add_geom(line, get_other_viz_state());
-  _bounds_viz_geom->add_geom(line, get_other_bounds_viz_state());
 }
 
 ////////////////////////////////////////////////////////////////////

+ 52 - 13
panda/src/collide/collisionPlane.cxx

@@ -25,7 +25,6 @@
 #include "collisionRay.h"
 #include "collisionSegment.h"
 #include "config_collide.h"
-
 #include "pointerToArray.h"
 #include "geomNode.h"
 #include "geom.h"
@@ -35,6 +34,10 @@
 #include "bamWriter.h"
 #include "omniBoundingVolume.h"
 #include "geomQuad.h"
+#include "qpgeom.h"
+#include "qpgeomTrifans.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionPlane::_type_handle;
 
@@ -322,20 +325,56 @@ fill_viz_geom() {
 
   static const double plane_scale = 10.0;
 
-  PTA_Vertexf verts;
-  verts.push_back(cp + p1 * plane_scale);
-  verts.push_back(cp + p2 * plane_scale);
-  verts.push_back(cp + p3 * plane_scale);
-  verts.push_back(cp + p4 * plane_scale);
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+
+    vertex.add_data3f(cp + p1 * plane_scale);
+    vertex.add_data3f(cp + p2 * plane_scale);
+    vertex.add_data3f(cp + p3 * plane_scale);
+    vertex.add_data3f(cp + p4 * plane_scale);
+    
+    PT(qpGeomTrifans) body = new qpGeomTrifans(qpGeomUsageHint::UH_static);
+    body->add_consecutive_vertices(0, 4);
+    body->close_primitive();
+
+    PT(qpGeomLinestrips) border = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+    border->add_consecutive_vertices(0, 4);
+    border->add_vertex(0);
+    border->close_primitive();
+
+    PT(qpGeom) geom1 = new qpGeom;
+    geom1->set_vertex_data(vdata);
+    geom1->add_primitive(body);
 
-  GeomQuad *quad = new GeomQuad;
-  quad->set_coords(verts);
-  quad->set_num_prims(1);
+    PT(qpGeom) geom2 = new qpGeom;
+    geom2->set_vertex_data(vdata);
+    geom2->add_primitive(border);
 
-  _viz_geom->add_geom(quad, get_solid_viz_state());
-  _viz_geom->add_geom(quad, get_wireframe_viz_state());
-  _bounds_viz_geom->add_geom(quad, get_solid_bounds_viz_state());
-  _bounds_viz_geom->add_geom(quad, get_wireframe_bounds_viz_state());
+    _viz_geom->add_geom(geom1, get_solid_viz_state());
+    _viz_geom->add_geom(geom2, get_wireframe_viz_state());
+
+    _bounds_viz_geom->add_geom(geom1, get_solid_bounds_viz_state());
+    _bounds_viz_geom->add_geom(geom2, get_wireframe_bounds_viz_state());
+
+  } else {
+    PTA_Vertexf verts;
+    verts.push_back(cp + p1 * plane_scale);
+    verts.push_back(cp + p2 * plane_scale);
+    verts.push_back(cp + p3 * plane_scale);
+    verts.push_back(cp + p4 * plane_scale);
+    
+    GeomQuad *quad = new GeomQuad;
+    quad->set_coords(verts);
+    quad->set_num_prims(1);
+    
+    _viz_geom->add_geom(quad, get_solid_viz_state());
+    _viz_geom->add_geom(quad, get_wireframe_viz_state());
+    _bounds_viz_geom->add_geom(quad, get_solid_bounds_viz_state());
+    _bounds_viz_geom->add_geom(quad, get_wireframe_bounds_viz_state());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 56 - 16
panda/src/collide/collisionPolygon.cxx

@@ -24,7 +24,6 @@
 #include "collisionRay.h"
 #include "collisionSegment.h"
 #include "config_collide.h"
-
 #include "cullTraverserData.h"
 #include "boundingSphere.h"
 #include "pointerToArray.h"
@@ -38,6 +37,10 @@
 #include "transformState.h"
 #include "clipPlaneAttrib.h"
 #include "nearly_zero.h"
+#include "qpgeom.h"
+#include "qpgeomTrifans.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomVertexWriter.h"
 
 #include <algorithm>
 
@@ -813,25 +816,62 @@ draw_polygon(GeomNode *viz_geom_node, GeomNode *bounds_viz_geom_node,
 
   LMatrix4f to_3d_mat;
   rederive_to_3d_mat(to_3d_mat);
-  PTA_Vertexf verts;
-  Points::const_iterator pi;
-  for (pi = points.begin(); pi != points.end(); ++pi) {
-    verts.push_back(to_3d((*pi)._p, to_3d_mat));
-  }
 
-  PTA_int lengths;
-  lengths.push_back(points.size());
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+
+    Points::const_iterator pi;
+    for (pi = points.begin(); pi != points.end(); ++pi) {
+      vertex.add_data3f(to_3d((*pi)._p, to_3d_mat));
+    }
+    
+    PT(qpGeomTrifans) body = new qpGeomTrifans(qpGeomUsageHint::UH_static);
+    body->add_consecutive_vertices(0, points.size());
+    body->close_primitive();
+
+    PT(qpGeomLinestrips) border = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+    border->add_consecutive_vertices(0, points.size());
+    border->add_vertex(0);
+    border->close_primitive();
 
-  GeomPolygon *polygon = new GeomPolygon;
-  polygon->set_coords(verts);
-  polygon->set_num_prims(1);
-  polygon->set_lengths(lengths);
+    PT(qpGeom) geom1 = new qpGeom;
+    geom1->set_vertex_data(vdata);
+    geom1->add_primitive(body);
 
-  viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_solid_viz_state());
-  viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_wireframe_viz_state());
+    PT(qpGeom) geom2 = new qpGeom;
+    geom2->set_vertex_data(vdata);
+    geom2->add_primitive(border);
 
-  bounds_viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_solid_bounds_viz_state());
-  bounds_viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_wireframe_bounds_viz_state());
+    _viz_geom->add_geom(geom1, ((CollisionPolygon *)this)->get_solid_viz_state());
+    _viz_geom->add_geom(geom2, ((CollisionPolygon *)this)->get_wireframe_viz_state());
+
+    _bounds_viz_geom->add_geom(geom1, ((CollisionPolygon *)this)->get_solid_bounds_viz_state());
+    _bounds_viz_geom->add_geom(geom2, ((CollisionPolygon *)this)->get_wireframe_bounds_viz_state());
+
+  } else {
+    PTA_Vertexf verts;
+    Points::const_iterator pi;
+    for (pi = points.begin(); pi != points.end(); ++pi) {
+      verts.push_back(to_3d((*pi)._p, to_3d_mat));
+    }
+    
+    PTA_int lengths;
+    lengths.push_back(points.size());
+    
+    GeomPolygon *polygon = new GeomPolygon;
+    polygon->set_coords(verts);
+    polygon->set_num_prims(1);
+    polygon->set_lengths(lengths);
+    
+    viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_solid_viz_state());
+    viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_wireframe_viz_state());
+    
+    bounds_viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_solid_bounds_viz_state());
+    bounds_viz_geom_node->add_geom(polygon, ((CollisionPolygon *)this)->get_wireframe_bounds_viz_state());
+  }
 }
 
 

+ 51 - 20
panda/src/collide/collisionRay.cxx

@@ -30,6 +30,9 @@
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamWriter.h"
+#include "qpgeom.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionRay::_type_handle;
 
@@ -149,34 +152,62 @@ fill_viz_geom() {
       << "Recomputing viz for " << *this << "\n";
   }
 
-  GeomLinestrip *line = new GeomLinestrip;
-  PTA_Vertexf verts;
-  PTA_Colorf colors;
-  PTA_int lengths;
-
   static const int num_points = 100;
   static const double scale = 100.0;
 
-  verts.reserve(num_points);
-  colors.reserve(num_points);
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+    
+    for (int i = 0; i < num_points; i++) {
+      double t = ((double)i / (double)num_points);
+      vertex.add_data3f(get_origin() + t * scale * get_direction());
+      
+      color.add_data4f(Colorf(1.0f, 1.0f, 1.0f, 1.0f) +
+                       t * Colorf(0.0f, 0.0f, 0.0f, -1.0f));
+    }
 
-  for (int i = 0; i < num_points; i++) {
-    double t = ((double)i / (double)num_points);
-    verts.push_back(get_origin() + t * scale * get_direction());
+    PT(qpGeomLinestrips) line = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+    line->add_next_vertices(num_points);
+    line->close_primitive();
 
-    colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f) +
-                     t * Colorf(0.0f, 0.0f, 0.0f, -1.0f));
-  }
-  line->set_coords(verts);
-  line->set_colors(colors, G_PER_VERTEX);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(line);
 
-  lengths.push_back(num_points-1);
-  line->set_lengths(lengths);
+    _viz_geom->add_geom(geom, get_other_viz_state());
+    _bounds_viz_geom->add_geom(geom, get_other_bounds_viz_state());
 
-  line->set_num_prims(1);
+  } else {
+    GeomLinestrip *line = new GeomLinestrip;
+    PTA_Vertexf verts;
+    PTA_Colorf colors;
+    PTA_int lengths;
 
-  _viz_geom->add_geom(line, get_other_viz_state());
-  _bounds_viz_geom->add_geom(line, get_other_bounds_viz_state());
+    verts.reserve(num_points);
+    colors.reserve(num_points);
+    
+    for (int i = 0; i < num_points; i++) {
+      double t = ((double)i / (double)num_points);
+      verts.push_back(get_origin() + t * scale * get_direction());
+      
+      colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f) +
+                       t * Colorf(0.0f, 0.0f, 0.0f, -1.0f));
+    }
+    line->set_coords(verts);
+    line->set_colors(colors, G_PER_VERTEX);
+    
+    lengths.push_back(num_points-1);
+    line->set_lengths(lengths);
+    
+    line->set_num_prims(1);
+    
+    _viz_geom->add_geom(line, get_other_viz_state());
+    _bounds_viz_geom->add_geom(line, get_other_bounds_viz_state());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 38 - 14
panda/src/collide/collisionSegment.cxx

@@ -21,7 +21,6 @@
 #include "collisionHandler.h"
 #include "collisionEntry.h"
 #include "config_collide.h"
-
 #include "geom.h"
 #include "lensNode.h"
 #include "geomNode.h"
@@ -32,6 +31,9 @@
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamWriter.h"
+#include "qpgeom.h"
+#include "qpgeomLines.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionSegment::_type_handle;
 
@@ -157,19 +159,41 @@ fill_viz_geom() {
       << "Recomputing viz for " << *this << "\n";
   }
 
-  GeomLine *segment = new GeomLine;
-  PTA_Vertexf verts;
-  PTA_Colorf colors;
-  verts.push_back(_a);
-  verts.push_back(_b);
-  colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-  segment->set_coords(verts);
-  segment->set_colors(colors, G_OVERALL);
-
-  segment->set_num_prims(1);
-
-  _viz_geom->add_geom(segment, get_other_viz_state());
-  _bounds_viz_geom->add_geom(segment, get_other_bounds_viz_state());
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    
+    vertex.add_data3f(_a);
+    vertex.add_data3f(_b);
+
+    PT(qpGeomLines) line = new qpGeomLines(qpGeomUsageHint::UH_static);
+    line->add_next_vertices(2);
+    line->close_primitive();
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(line);
+
+    _viz_geom->add_geom(geom, get_other_viz_state());
+    _bounds_viz_geom->add_geom(geom, get_other_bounds_viz_state());
+
+  } else {
+    GeomLine *segment = new GeomLine;
+    PTA_Vertexf verts;
+    PTA_Colorf colors;
+    verts.push_back(_a);
+    verts.push_back(_b);
+    colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+    segment->set_coords(verts);
+    segment->set_colors(colors, G_OVERALL);
+    
+    segment->set_num_prims(1);
+
+    _viz_geom->add_geom(segment, get_other_viz_state());
+    _bounds_viz_geom->add_geom(segment, get_other_bounds_viz_state());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 56 - 23
panda/src/collide/collisionSphere.cxx

@@ -24,7 +24,6 @@
 #include "collisionHandler.h"
 #include "collisionEntry.h"
 #include "config_collide.h"
-
 #include "boundingSphere.h"
 #include "datagram.h"
 #include "datagramIterator.h"
@@ -34,6 +33,9 @@
 #include "nearly_zero.h"
 #include "cmath.h"
 #include "mathNumbers.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionSphere::_type_handle;
 
@@ -325,32 +327,63 @@ fill_viz_geom() {
   static const int num_slices = 16;
   static const int num_stacks = 8;
 
-  GeomTristrip *sphere = new GeomTristrip;
-  PTA_Vertexf verts;
-  PTA_int lengths;
-  verts.reserve((num_stacks * 2) * num_slices);
-  lengths.reserve(num_slices);
-
-  for (int sl = 0; sl < num_slices; sl++) {
-    float longitude0 = (float)sl / (float)num_slices;
-    float longitude1 = (float)(sl + 1) / (float)num_slices;
-    verts.push_back(compute_point(0.0, longitude0));
-    for (int st = 1; st < num_stacks; st++) {
-      float latitude = (float)st / (float)num_stacks;
-      verts.push_back(compute_point(latitude, longitude0));
-      verts.push_back(compute_point(latitude, longitude1));
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    for (int sl = 0; sl < num_slices; ++sl) {
+      float longitude0 = (float)sl / (float)num_slices;
+      float longitude1 = (float)(sl + 1) / (float)num_slices;
+      vertex.add_data3f(compute_point(0.0, longitude0));
+      for (int st = 1; st < num_stacks; ++st) {
+        float latitude = (float)st / (float)num_stacks;
+        vertex.add_data3f(compute_point(latitude, longitude0));
+        vertex.add_data3f(compute_point(latitude, longitude1));
+      }
+      vertex.add_data3f(compute_point(1.0, longitude0));
+
+      strip->add_next_vertices(num_stacks * 2);
+      strip->close_primitive();
     }
-    verts.push_back(compute_point(1.0, longitude0));
 
-    lengths.push_back(num_stacks * 2);
-  }
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
 
-  sphere->set_coords(verts);
-  sphere->set_lengths(lengths);
-  sphere->set_num_prims(num_slices);
+    _viz_geom->add_geom(geom, get_solid_viz_state());
+    _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
 
-  _viz_geom->add_geom(sphere, get_solid_viz_state());
-  _bounds_viz_geom->add_geom(sphere, get_solid_bounds_viz_state());
+  } else {
+    GeomTristrip *sphere = new GeomTristrip;
+    PTA_Vertexf verts;
+    PTA_int lengths;
+    verts.reserve((num_stacks * 2) * num_slices);
+    lengths.reserve(num_slices);
+    
+    for (int sl = 0; sl < num_slices; sl++) {
+      float longitude0 = (float)sl / (float)num_slices;
+      float longitude1 = (float)(sl + 1) / (float)num_slices;
+      verts.push_back(compute_point(0.0, longitude0));
+      for (int st = 1; st < num_stacks; st++) {
+        float latitude = (float)st / (float)num_stacks;
+        verts.push_back(compute_point(latitude, longitude0));
+        verts.push_back(compute_point(latitude, longitude1));
+      }
+      verts.push_back(compute_point(1.0, longitude0));
+      
+      lengths.push_back(num_stacks * 2);
+    }
+    
+    sphere->set_coords(verts);
+    sphere->set_lengths(lengths);
+    sphere->set_num_prims(num_slices);
+    
+    _viz_geom->add_geom(sphere, get_solid_viz_state());
+    _bounds_viz_geom->add_geom(sphere, get_solid_bounds_viz_state());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 93 - 37
panda/src/collide/collisionTube.cxx

@@ -24,7 +24,6 @@
 #include "collisionHandler.h"
 #include "collisionEntry.h"
 #include "config_collide.h"
-
 #include "look_at.h"
 #include "geom.h"
 #include "geomNode.h"
@@ -36,6 +35,9 @@
 #include "bamWriter.h"
 #include "cmath.h"
 #include "transformState.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle CollisionTube::_type_handle;
 
@@ -389,54 +391,108 @@ fill_viz_geom() {
   LVector3f direction = (_b - _a);
   float length = direction.length();
 
-  PTA_Vertexf verts;
-  PTA_int lengths;
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("collision", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    // Generate the first endcap.
+    static const int num_slices = 8;
+    static const int num_rings = 4;
+    int ri, si;
+    for (ri = 0; ri < num_rings; ri++) {
+      for (si = 0; si <= num_slices; si++) {
+        vertex.add_data3f(calc_sphere1_vertex(ri, si, num_rings, num_slices));
+        vertex.add_data3f(calc_sphere1_vertex(ri + 1, si, num_rings, num_slices));
+      }
+      strip->add_next_vertices((num_slices + 1) * 2);
+      strip->close_primitive();
+    }
 
-  // Generate the first endcap.
-  static const int num_slices = 8;
-  static const int num_rings = 4;
-  int ri, si;
-  for (ri = 0; ri < num_rings; ri++) {
+    // Now the cylinder sides.
     for (si = 0; si <= num_slices; si++) {
-      verts.push_back(calc_sphere1_vertex(ri, si, num_rings, num_slices));
-      verts.push_back(calc_sphere1_vertex(ri + 1, si, num_rings, num_slices));
+      vertex.add_data3f(calc_sphere1_vertex(num_rings, si, num_rings, num_slices));
+      vertex.add_data3f(calc_sphere2_vertex(num_rings, si, num_rings, num_slices,
+                                          length));
+    }
+    strip->add_next_vertices((num_slices + 1) * 2);
+    strip->close_primitive();
+
+    // And the second endcap.
+    for (ri = num_rings - 1; ri >= 0; ri--) {
+      for (si = 0; si <= num_slices; si++) {
+        vertex.add_data3f(calc_sphere2_vertex(ri + 1, si, num_rings, num_slices, length));
+        vertex.add_data3f(calc_sphere2_vertex(ri, si, num_rings, num_slices, length));
+      }
+      strip->add_next_vertices((num_slices + 1) * 2);
+      strip->close_primitive();
     }
-    lengths.push_back((num_slices + 1) * 2);
-  }
 
-  // Now the cylinder sides.
-  for (si = 0; si <= num_slices; si++) {
-    verts.push_back(calc_sphere1_vertex(num_rings, si, num_rings, num_slices));
-    verts.push_back(calc_sphere2_vertex(num_rings, si, num_rings, num_slices,
-                                        length));
-  }
-  lengths.push_back((num_slices + 1) * 2);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    // Now transform the vertices to their actual location.
+    LMatrix4f mat;
+    look_at(mat, direction, LVector3f(0.0f, 0.0f, 1.0f), CS_zup_right);
+    mat.set_row(3, _a);
+    geom->transform_vertices(mat);
+
+    _viz_geom->add_geom(geom, get_solid_viz_state());
+    _bounds_viz_geom->add_geom(geom, get_solid_bounds_viz_state());
 
-  // And the second endcap.
-  for (ri = num_rings - 1; ri >= 0; ri--) {
+  } else {
+    PTA_Vertexf verts;
+    PTA_int lengths;
+
+    // Generate the first endcap.
+    static const int num_slices = 8;
+    static const int num_rings = 4;
+    int ri, si;
+    for (ri = 0; ri < num_rings; ri++) {
+      for (si = 0; si <= num_slices; si++) {
+        verts.push_back(calc_sphere1_vertex(ri, si, num_rings, num_slices));
+        verts.push_back(calc_sphere1_vertex(ri + 1, si, num_rings, num_slices));
+      }
+      lengths.push_back((num_slices + 1) * 2);
+    }
+
+    // Now the cylinder sides.
     for (si = 0; si <= num_slices; si++) {
-      verts.push_back(calc_sphere2_vertex(ri + 1, si, num_rings, num_slices, length));
-      verts.push_back(calc_sphere2_vertex(ri, si, num_rings, num_slices, length));
+      verts.push_back(calc_sphere1_vertex(num_rings, si, num_rings, num_slices));
+      verts.push_back(calc_sphere2_vertex(num_rings, si, num_rings, num_slices,
+                                          length));
     }
     lengths.push_back((num_slices + 1) * 2);
-  }
 
-  // Now transform the vertices to their actual location.
-  LMatrix4f mat;
-  look_at(mat, direction, LVector3f(0.0f, 0.0f, 1.0f), CS_zup_right);
-  mat.set_row(3, _a);
+    // And the second endcap.
+    for (ri = num_rings - 1; ri >= 0; ri--) {
+      for (si = 0; si <= num_slices; si++) {
+        verts.push_back(calc_sphere2_vertex(ri + 1, si, num_rings, num_slices, length));
+        verts.push_back(calc_sphere2_vertex(ri, si, num_rings, num_slices, length));
+      }
+      lengths.push_back((num_slices + 1) * 2);
+    }
 
-  for (size_t i = 0; i < verts.size(); i++) {
-    verts[i] = verts[i] * mat;
-  }
+    // Now transform the vertices to their actual location.
+    LMatrix4f mat;
+    look_at(mat, direction, LVector3f(0.0f, 0.0f, 1.0f), CS_zup_right);
+    mat.set_row(3, _a);
 
-  GeomTristrip *tube = new GeomTristrip;
-  tube->set_coords(verts);
-  tube->set_num_prims(lengths.size());
-  tube->set_lengths(lengths);
+    for (size_t i = 0; i < verts.size(); i++) {
+      verts[i] = verts[i] * mat;
+    }
 
-  _viz_geom->add_geom(tube, get_solid_viz_state());
-  _bounds_viz_geom->add_geom(tube, get_solid_bounds_viz_state());
+    GeomTristrip *tube = new GeomTristrip;
+    tube->set_coords(verts);
+    tube->set_num_prims(lengths.size());
+    tube->set_lengths(lengths);
+
+    _viz_geom->add_geom(tube, get_solid_viz_state());
+    _bounds_viz_geom->add_geom(tube, get_solid_bounds_viz_state());
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/framework/windowFramework.cxx

@@ -1060,7 +1060,7 @@ load_image_as_model(const Filename &filename) {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      (string(), qpGeomVertexFormat::get_v3t2(),
+      (string(), qpGeomVertexFormat::get_v3cpt2(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());

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

@@ -2635,7 +2635,7 @@ GeomContext *CLP(GraphicsStateGuardian)::
 prepare_geom(Geom *geom) {
   // Temporary test until the experimental Geom rewrite becomes the
   // actual Geom implementation.
-  if (geom->is_exact_type(qpGeom::get_class_type())) {
+  if (geom->is_of_type(qpGeom::get_class_type())) {
     CLP(GeomContext) *ggc = new CLP(GeomContext)(geom);
     return ggc;
 

+ 10 - 0
panda/src/gobj/config_gobj.cxx

@@ -167,6 +167,16 @@ ConfigVariableBool use_qpgeom
           "underway.  Set this true if you want to use the experimental "
           "code.  You don't really want to set this true."));
 
+ConfigVariableBool support_old_geom
+("support-old-geom", true,
+ PRC_DESC("A temporary variable while the experimental Geom rewrite is "
+          "underway.  Set this false if you DON't want to see anything "
+          "rendered from a legacy Geom.  This is intended to help "
+          "prove visually that the experimental Geoms are actually "
+          "being used.  You don't really want to set this false, and "
+          "you certainly don't want to monkey with it if you haven't "
+          "also set use-qpgeom true."));
+
 
 ConfigVariableEnum<BamTextureMode> bam_texture_mode
 ("bam-texture-mode", BTM_relative,

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

@@ -59,6 +59,7 @@ extern EXPCL_PANDA ConfigVariableBool display_list_animation;
 extern EXPCL_PANDA ConfigVariableBool connect_triangle_strips;
 
 extern EXPCL_PANDA ConfigVariableBool use_qpgeom;
+extern EXPCL_PANDA ConfigVariableBool support_old_geom;
 
 extern EXPCL_PANDA ConfigVariableEnum<BamTextureMode> bam_texture_mode;
 extern EXPCL_PANDA ConfigVariableEnum<AutoTextureScale> textures_power_2;

+ 4 - 1
panda/src/gobj/geom.cxx

@@ -303,7 +303,7 @@ operator = (const Geom &copy) {
 
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::transform_vertices
-//       Access: Published
+//       Access: Published, Virtual
 //  Description: Applies the indicated transform to all of the
 //               vertices in the Geom.  If the Geom happens to share a
 //               vertex table with another Geom, this operation will
@@ -917,6 +917,9 @@ release_all() {
 void Geom::
 draw(GraphicsStateGuardianBase *gsg, 
      const qpGeomMunger *, const qpGeomVertexData *) const {
+  if (!support_old_geom) {
+    return;
+  }
   PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
   if (is_dirty()) {
     ((Geom *)this)->config(); 

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

@@ -135,7 +135,7 @@ public:
   virtual Geom *make_copy() const=0;
 
 PUBLISHED:
-  void transform_vertices(const LMatrix4f &mat);
+  virtual void transform_vertices(const LMatrix4f &mat);
 
   void set_coords(const PTA_Vertexf &coords,
                   const PTA_ushort &vindex = PTA_ushort());

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

@@ -18,6 +18,7 @@
 
 #include "qpgeom.h"
 #include "qpgeomVertexReader.h"
+#include "qpgeomVertexRewriter.h"
 #include "pStatTimer.h"
 #include "bamReader.h"
 #include "bamWriter.h"
@@ -224,6 +225,43 @@ get_num_bytes() const {
   return num_bytes;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::transform_vertices
+//       Access: Published, Virtual
+//  Description: Applies the indicated transform to all of the
+//               vertices in the Geom.  If the Geom happens to share a
+//               vertex table with another Geom, this operation will
+//               duplicate the vertex table instead of breaking the
+//               other Geom; however, if multiple Geoms with shared
+//               tables are transformed by the same matrix, they will
+//               no longer share tables after the operation.  Consider
+//               using the GeomTransformer if you will be applying the
+//               same transform to multiple Geoms.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+transform_vertices(const LMatrix4f &mat) {
+  PT(qpGeomVertexData) new_data = modify_vertex_data();
+  CPT(qpGeomVertexFormat) format = new_data->get_format();
+  
+  int ci;
+  for (ci = 0; ci < format->get_num_points(); ci++) {
+    qpGeomVertexRewriter data(new_data, format->get_point(ci));
+    
+    while (!data.is_at_end()) {
+      const LPoint3f &point = data.get_data3f();
+      data.set_data3f(point * mat);
+    }
+  }
+  for (ci = 0; ci < format->get_num_vectors(); ci++) {
+    qpGeomVertexRewriter data(new_data, format->get_vector(ci));
+    
+    while (!data.is_at_end()) {
+      const LVector3f &vector = data.get_data3f();
+      data.set_data3f(normalize(vector * mat));
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::munge_geom
 //       Access: Published

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

@@ -84,6 +84,8 @@ PUBLISHED:
   int get_num_bytes() const;
   INLINE UpdateSeq get_modified() const;
 
+  virtual void transform_vertices(const LMatrix4f &mat);
+
   void munge_geom(const qpGeomMunger *munger,
                   CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const;
 

+ 30 - 1
panda/src/gobj/qpgeomPrimitive.cxx

@@ -101,7 +101,7 @@ add_vertex(int vertex) {
 
   int num_primitives = get_num_primitives();
   if (num_primitives > 0 &&
-      cdata->_vertices.size() == get_primitive_end(num_primitives - 1)) {
+      (int)cdata->_vertices.size() == get_primitive_end(num_primitives - 1)) {
     // If we are beginning a new primitive, give the derived class a
     // chance to insert some degenerate vertices.
     append_unused_vertices(cdata->_vertices, vertex);
@@ -145,6 +145,15 @@ add_consecutive_vertices(int start, int num_vertices) {
   nassertv((int)short_start == start && (int)short_end == end);
 
   CDWriter cdata(_cycler);
+
+  int num_primitives = get_num_primitives();
+  if (num_primitives > 0 &&
+      (int)cdata->_vertices.size() == get_primitive_end(num_primitives - 1)) {
+    // If we are beginning a new primitive, give the derived class a
+    // chance to insert some degenerate vertices.
+    append_unused_vertices(cdata->_vertices, start);
+  }
+
   for (unsigned short v = short_start; v <= short_end; ++v) {
     cdata->_vertices.push_back(v);
   }
@@ -170,6 +179,26 @@ add_consecutive_vertices(int start, int num_vertices) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::add_next_vertices
+//       Access: Published
+//  Description: Adds the next n vertices in sequence, beginning from
+//               the last vertex added to the primitive + 1.
+//
+//               This is most useful when you are building up a
+//               primitive and a GeomVertexData at the same time, and
+//               you just want the primitive to reference the first n
+//               vertices from the data, then the next n, and so on.
+////////////////////////////////////////////////////////////////////
+void qpGeomPrimitive::
+add_next_vertices(int num_vertices) {
+  if (get_num_vertices() == 0) {
+    add_consecutive_vertices(0, num_vertices);
+  } else {
+    add_consecutive_vertices(get_vertex(get_num_vertices() - 1) + 1, num_vertices);
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::close_primitive
 //       Access: Published

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

@@ -116,6 +116,7 @@ PUBLISHED:
   INLINE int get_vertex(int i) const;
   void add_vertex(int vertex);
   void add_consecutive_vertices(int start, int num_vertices);
+  void add_next_vertices(int num_vertices);
   bool close_primitive();
   void clear_vertices();
 

+ 20 - 8
panda/src/gobj/qpgeomVertexArrayData.I

@@ -40,16 +40,15 @@ get_usage_hint() const {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexArrayData::get_data
+//     Function: qpGeomVertexArrayData::has_column
 //       Access: Published
-//  Description: Returns a const pointer to the actual vertex data,
-//               for application code to directly examine (but not
-//               modify).
+//  Description: Returns true if the array has the named column,
+//               false otherwise.  This is really just a shortcut for
+//               asking the same thing from the format.
 ////////////////////////////////////////////////////////////////////
-INLINE CPTA_uchar qpGeomVertexArrayData::
-get_data() const {
-  CDReader cdata(_cycler);
-  return cdata->_data;
+INLINE bool qpGeomVertexArrayData::
+has_column(const InternalName *name) const {
+  return _array_format->has_column(name);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -100,6 +99,19 @@ get_modified() const {
   return cdata->_modified;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayData::get_data
+//       Access: Public
+//  Description: Returns a const pointer to the actual vertex data,
+//               for application code to directly examine (but not
+//               modify).
+////////////////////////////////////////////////////////////////////
+INLINE CPTA_uchar qpGeomVertexArrayData::
+get_data() const {
+  CDReader cdata(_cycler);
+  return cdata->_data;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayData::CData::Constructor
 //       Access: Public

+ 44 - 40
panda/src/gobj/qpgeomVertexArrayData.cxx

@@ -83,43 +83,6 @@ qpGeomVertexArrayData::
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexArrayData::modify_data
-//       Access: Published
-//  Description: Returns a modifiable pointer to the actual vertex
-//               array, so that application code may directly
-//               manipulate the vertices.
-////////////////////////////////////////////////////////////////////
-PTA_uchar qpGeomVertexArrayData::
-modify_data() {
-  // 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);
-
-  if (cdata->_data.get_ref_count() > 1) {
-    PTA_uchar orig_data = cdata->_data;
-    cdata->_data = PTA_uchar();
-    cdata->_data.v() = orig_data.v();
-  }
-  cdata->_modified = qpGeom::get_next_modified();
-
-  return cdata->_data;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeomVertexArrayData::set_data
-//       Access: Published
-//  Description: Replaces the vertex data array with a completely new
-//               array.
-////////////////////////////////////////////////////////////////////
-void qpGeomVertexArrayData::
-set_data(CPTA_uchar array) {
-  CDWriter cdata(_cycler);
-  cdata->_data = (PTA_uchar &)array;
-  cdata->_modified = qpGeom::get_next_modified();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayData::set_num_vertices
 //       Access: Published
@@ -132,6 +95,10 @@ set_data(CPTA_uchar array) {
 //               The return value is true if the number of vertices
 //               was changed, false if the object already contained n
 //               vertices (or if there was some error).
+//
+//               The new vertex data is initialized to 0, including
+//               the "color" column (but see
+//               GeomVertexData::set_num_vertices()).
 ////////////////////////////////////////////////////////////////////
 bool qpGeomVertexArrayData::
 set_num_vertices(int n) {
@@ -146,7 +113,7 @@ set_num_vertices(int n) {
       // so we're just going to make a copy.
       PTA_uchar new_data;
       new_data.reserve(n * stride);
-      new_data.insert(new_data.end(), n * stride, uchar());
+      new_data.insert(new_data.end(), n * stride, 0);
       memcpy(new_data, cdata->_data, 
              min((size_t)(n * stride), cdata->_data.size()));
       cdata->_data = new_data;
@@ -155,7 +122,7 @@ set_num_vertices(int n) {
       // We've got the only reference to the data, so we can change
       // it directly.
       if (delta > 0) {
-        cdata->_data.insert(cdata->_data.end(), delta * stride, uchar());
+        cdata->_data.insert(cdata->_data.end(), delta * stride, 0);
         
       } else {
         cdata->_data.erase(cdata->_data.begin() + n * stride, 
@@ -171,9 +138,46 @@ set_num_vertices(int n) {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayData::modify_data
+//       Access: Public
+//  Description: Returns a modifiable pointer to the actual vertex
+//               array, so that application code may directly
+//               manipulate the vertices.
+////////////////////////////////////////////////////////////////////
+PTA_uchar qpGeomVertexArrayData::
+modify_data() {
+  // 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);
+
+  if (cdata->_data.get_ref_count() > 1) {
+    PTA_uchar orig_data = cdata->_data;
+    cdata->_data = PTA_uchar();
+    cdata->_data.v() = orig_data.v();
+  }
+  cdata->_modified = qpGeom::get_next_modified();
+
+  return cdata->_data;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomVertexArrayData::set_data
+//       Access: Public
+//  Description: Replaces the vertex data array with a completely new
+//               array.
+////////////////////////////////////////////////////////////////////
+void qpGeomVertexArrayData::
+set_data(CPTA_uchar array) {
+  CDWriter cdata(_cycler);
+  cdata->_data = (PTA_uchar &)array;
+  cdata->_modified = qpGeom::get_next_modified();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexArrayData::prepare
-//       Access: Published
+//       Access: Public
 //  Description: Indicates that the data should be enqueued to be
 //               prepared in the indicated prepared_objects at the
 //               beginning of the next frame.  This will ensure the

+ 12 - 5
panda/src/gobj/qpgeomVertexArrayData.h

@@ -47,8 +47,12 @@ class GraphicsStateGuardianBase;
 //               It also closely correlates with the concept of a
 //               vertex buffer.
 //
-//               This object is just a block of data.  See
-//               GeomVertexData for the organizing structure.
+//               This object is just a block of data.  In general, you
+//               should not be directly messing with this object from
+//               application code.  See GeomVertexData for the
+//               organizing structure, and see
+//               GeomVertexReader/Writer/Rewriter for high-level tools
+//               to manipulate the actual vertex data.
 //
 //               This is part of the experimental Geom rewrite.
 ////////////////////////////////////////////////////////////////////
@@ -68,9 +72,7 @@ PUBLISHED:
   INLINE const qpGeomVertexArrayFormat *get_array_format() const;
   INLINE qpGeomUsageHint::UsageHint get_usage_hint() const;
 
-  INLINE CPTA_uchar get_data() const;
-  PTA_uchar modify_data();
-  void set_data(CPTA_uchar data);
+  INLINE bool has_column(const InternalName *name) const;
 
   INLINE int get_num_vertices() const;
   bool set_num_vertices(int n);
@@ -79,6 +81,11 @@ PUBLISHED:
   INLINE int get_data_size_bytes() const;
   INLINE UpdateSeq get_modified() const;
 
+public:
+  INLINE CPTA_uchar get_data() const;
+  PTA_uchar modify_data();
+  void set_data(CPTA_uchar data);
+
   void prepare(PreparedGraphicsObjects *prepared_objects);
 
 public:

+ 11 - 1
panda/src/gobj/qpgeomVertexData.I

@@ -91,11 +91,21 @@ has_column(const InternalName *name) const {
 //       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.
+//
+//               The new vertex data is initialized to 0, except for
+//               the "color" column, which is initialized to (1, 1, 1,
+//               1).
 //
 //               The return value is true if the number of vertices
 //               was changed, false if the object already contained n
 //               vertices (or if there was some error).
+//
+//               Although this method is Published, application code
+//               only very rarely has any need to call it.  Instead,
+//               you should use the GeomVertexWriter to build up the
+//               vertices in a GeomVertexData object automatically,
+//               without need to explicitly set the number of
+//               vertices.
 ////////////////////////////////////////////////////////////////////
 INLINE bool qpGeomVertexData::
 set_num_vertices(int n) {

+ 51 - 1
panda/src/gobj/qpgeomVertexData.cxx

@@ -170,7 +170,8 @@ clear_vertices() {
 //               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.
+//               should be kept in sync--use set_num_vertices()
+//               instead.
 ////////////////////////////////////////////////////////////////////
 qpGeomVertexArrayData *qpGeomVertexData::
 modify_array(int i) {
@@ -1024,17 +1025,66 @@ do_set_num_vertices(int n, qpGeomVertexData::CDWriter &cdata) {
 
   bool any_changed = false;
 
+  int color_array = -1;
+  int orig_color_vertices = -1;
+
   for (size_t i = 0; i < cdata->_arrays.size(); i++) {
     if (cdata->_arrays[i]->get_num_vertices() != n) {
       // Copy-on-write.
       if (cdata->_arrays[i]->get_ref_count() > 1) {
         cdata->_arrays[i] = new qpGeomVertexArrayData(*cdata->_arrays[i]);
       }
+      if (cdata->_arrays[i]->has_column(InternalName::get_color())) {
+        color_array = i;
+        orig_color_vertices = cdata->_arrays[i]->get_num_vertices();
+      }
       cdata->_arrays[i]->set_num_vertices(n);
       any_changed = true;
     }
   }
 
+  if (color_array >= 0 && orig_color_vertices < n) {
+    // We have just added some vertices, fill the "color" column with
+    // (1, 1, 1, 1), for the programmer's convenience.
+    qpGeomVertexArrayData *array_data = cdata->_arrays[color_array];
+    const qpGeomVertexColumn *column = 
+      array_data->get_array_format()->get_column(InternalName::get_color());
+    int stride = array_data->get_array_format()->get_stride();
+    unsigned char *start = 
+      array_data->modify_data() + column->get_start();
+    unsigned char *stop = start + array_data->get_data_size_bytes();
+    unsigned char *pointer = start + stride * orig_color_vertices;
+    int num_values = column->get_num_values();
+
+    switch (column->get_numeric_type()) {
+    case qpGeomVertexColumn::NT_packed_dcba:
+    case qpGeomVertexColumn::NT_packed_dabc:
+    case qpGeomVertexColumn::NT_uint8:
+      while (pointer < stop) {
+        memset(pointer, 0xff, num_values);
+        pointer += stride;
+      }
+      break;
+
+    case qpGeomVertexColumn::NT_uint16:
+      while (pointer < stop) {
+        memset(pointer, 0xff, num_values * 2);
+        pointer += stride;
+      }
+      break;
+
+    case qpGeomVertexColumn::NT_float32:
+      while (pointer < stop) {
+        PN_float32 *pi = (PN_float32 *)pointer;
+        for (int i = 0; i < num_values; i++) {
+          pi[i] = 1.0f;
+        }
+        pointer += stride;
+      }
+      break;
+    }          
+  }
+
   if (any_changed) {
     cdata->_modified = qpGeom::get_next_modified();
     cdata->_animated_vertices.clear();

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

@@ -64,6 +64,12 @@ class qpGeomVertexColumn;
 //               single table of vertices, where each vertex is
 //               represented by one row of the table.
 //
+//               In general, application code should not attempt to
+//               directly manipulate the vertex data through this
+//               structure; instead, use the GeomVertexReader,
+//               GeomVertexWriter, and GeomVertexRewriter objects to
+//               read and write vertex data at a high level.
+//
 //               This is part of the experimental Geom rewrite.
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA qpGeomVertexData : public TypedWritableReferenceCount {

+ 2 - 2
panda/src/gobj/qpgeomVertexReader.I

@@ -382,8 +382,8 @@ set_pointer(int vertex) {
 ////////////////////////////////////////////////////////////////////
 INLINE const unsigned char *qpGeomVertexReader::
 inc_pointer() {
-  nassertr(_read_vertex < _num_vertices, NULL);
-  nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _read_vertex, NULL);
+  nassertr(_read_vertex < _num_vertices, empty_buffer);
+  nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _read_vertex, empty_buffer);
 
   const unsigned char *orig_pointer = _pointer;
   _pointer += _stride;

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

@@ -18,6 +18,13 @@
 
 #include "qpgeomVertexReader.h"
 
+
+#ifndef NDEBUG
+  // This is defined just for the benefit of having something non-NULL
+  // to return from a nassertr() call.
+const unsigned char qpGeomVertexReader::empty_buffer[100] = { 0 };
+#endif
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexReader::set_column
 //       Access: Published

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

@@ -116,6 +116,12 @@ private:
 
   Reader *_reader;
 
+#ifndef NDEBUG
+  // This is defined just for the benefit of having something non-NULL
+  // to return from a nassertr() call.
+  static const unsigned char empty_buffer[100];
+#endif
+
   // This nested class provides the implementation for unpacking data
   // in a very general way, but also provides the hooks for
   // implementing the common, very direct code paths (for instance,

+ 2 - 2
panda/src/gobj/qpgeomVertexWriter.I

@@ -686,8 +686,8 @@ set_pointer(int vertex) {
 ////////////////////////////////////////////////////////////////////
 INLINE unsigned char *qpGeomVertexWriter::
 inc_pointer() {
-  nassertr(_write_vertex < _num_vertices, NULL);
-  nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _write_vertex, NULL);
+  nassertr(_write_vertex < _num_vertices, empty_buffer);
+  nassertr(_pointer == _vertex_data->get_array(_array)->get_data() + _column->get_start() + _stride * _write_vertex, empty_buffer);
 
   unsigned char *orig_pointer = _pointer;
   _pointer += _stride;

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

@@ -18,6 +18,13 @@
 
 #include "qpgeomVertexWriter.h"
 
+
+#ifndef NDEBUG
+  // This is defined just for the benefit of having something non-NULL
+  // to return from a nassertr() call.
+unsigned char qpGeomVertexWriter::empty_buffer[100] = { 0 };
+#endif
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomVertexWriter::set_column
 //       Access: Published

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

@@ -152,6 +152,12 @@ private:
 
   Writer *_writer;
 
+#ifndef NDEBUG
+  // This is defined just for the benefit of having something non-NULL
+  // to return from a nassertr() call.
+  static unsigned char empty_buffer[100];
+#endif
+
   // This nested class provides the implementation for unpacking data
   // in a very general way, but also provides the hooks for
   // implementing the common, very direct code paths (for instance,

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

@@ -37,7 +37,7 @@ munge_geom(const qpGeomMunger *munger) {
   if (_geom != (Geom *)NULL) {
     // Temporary test and dcast until the experimental Geom rewrite
     // becomes the actual Geom rewrite.
-    if (_geom->is_exact_type(qpGeom::get_class_type())) {
+    if (_geom->is_of_type(qpGeom::get_class_type())) {
       _munger = munger;
       CPT(qpGeom) qpgeom = DCAST(qpGeom, _geom);
       qpgeom->munge_geom(munger, qpgeom, _munged_data);

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

@@ -354,7 +354,7 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
     const Geom *geom = get_geom(i);
     
     // Temporary test until the experimental Geom rewrite is final.
-    if (geom->is_exact_type(qpGeom::get_class_type())) {
+    if (geom->is_of_type(qpGeom::get_class_type())) {
       const qpGeom *qpgeom = DCAST(qpGeom, geom);
       qpgeom->calc_tight_bounds(min_point, max_point, found_any,
                                 qpgeom->get_vertex_data()->animate_vertices(),

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

@@ -53,7 +53,7 @@ transform_vertices(Geom *geom, const LMatrix4f &mat) {
 
   nassertr(geom != (Geom *)NULL, false);
 
-  if (geom->is_exact_type(qpGeom::get_class_type())) {
+  if (geom->is_of_type(qpGeom::get_class_type())) {
     qpGeom *qpgeom = DCAST(qpGeom, geom);
 
     qpSourceVertices sv;
@@ -194,7 +194,7 @@ transform_texcoords(Geom *geom, const InternalName *from_name,
   bool transformed = false;
 
   nassertr(geom != (Geom *)NULL, false);
-  if (geom->is_exact_type(qpGeom::get_class_type())) {
+  if (geom->is_of_type(qpGeom::get_class_type())) {
     qpGeom *qpgeom = DCAST(qpGeom, geom);
 
     qpSourceTexCoords st;
@@ -314,7 +314,7 @@ bool GeomTransformer::
 set_color(Geom *geom, const Colorf &color) {
   bool transformed = false;
 
-  if (geom->is_exact_type(qpGeom::get_class_type())) {
+  if (geom->is_of_type(qpGeom::get_class_type())) {
     qpGeom *qpgeom = DCAST(qpGeom, geom);
 
     qpSourceColors sc;
@@ -389,7 +389,7 @@ transform_colors(Geom *geom, const LVecBase4f &scale) {
 
   nassertr(geom != (Geom *)NULL, false);
 
-  if (geom->is_exact_type(qpGeom::get_class_type())) {
+  if (geom->is_of_type(qpGeom::get_class_type())) {
     qpGeom *qpgeom = DCAST(qpGeom, geom);
 
     qpSourceColors sc;

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

@@ -101,9 +101,9 @@ private:
   typedef pmap<qpSourceColors, CPT(qpGeomVertexData) > NewColors;
 
   // We have two concepts of colors: the "fixed" colors, which are
-  // slapped in complete replacement of the original colors (e.g. via
-  // a ColorAttrib), and the "transformed" colors, which are modified
-  // from the original colors (e.g. via a ColorScaleAttrib).
+  // slapped in as a complete replacement of the original colors
+  // (e.g. via a ColorAttrib), and the "transformed" colors, which are
+  // modified from the original colors (e.g. via a ColorScaleAttrib).
   NewColors _qpfcolors, _qptcolors;
 
 
@@ -138,9 +138,9 @@ private:
   TexCoords _texcoords;
 
   // We have two concepts of colors: the "fixed" colors, which are
-  // slapped in complete replacement of the original colors (e.g. via
-  // a ColorAttrib), and the "transformed" colors, which are modified
-  // from the original colors (e.g. via a ColorScaleAttrib).
+  // slapped in as a complete replacement of the original colors
+  // (e.g. via a ColorAttrib), and the "transformed" colors, which are
+  // modified from the original colors (e.g. via a ColorScaleAttrib).
   typedef pmap<Colorf, PTA_Colorf> FColors;
   FColors _fcolors;
 

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

@@ -19,6 +19,7 @@
     dynamicTextPage.I dynamicTextPage.h \
     fontPool.I fontPool.h \
     geomTextGlyph.I geomTextGlyph.h \
+    qpgeomTextGlyph.I qpgeomTextGlyph.h \
     staticTextFont.I staticTextFont.h \
     textAssembler.I textAssembler.h \
     textFont.I textFont.h \
@@ -35,6 +36,7 @@
     dynamicTextPage.cxx \
     fontPool.cxx \
     geomTextGlyph.cxx \
+    qpgeomTextGlyph.cxx \
     staticTextFont.cxx \
     textAssembler.cxx \
     textFont.cxx textGlyph.cxx \
@@ -49,6 +51,7 @@
     dynamicTextPage.I dynamicTextPage.h \
     fontPool.I fontPool.h \
     geomTextGlyph.I geomTextGlyph.h \
+    qpgeomTextGlyph.I qpgeomTextGlyph.h \
     staticTextFont.I staticTextFont.h \
     textAssembler.I textAssembler.h \
     textFont.I textFont.h \

+ 4 - 0
panda/src/text/config_text.cxx

@@ -24,6 +24,7 @@
 #include "dynamicTextFont.h"
 #include "dynamicTextPage.h"
 #include "geomTextGlyph.h"
+#include "qpgeomTextGlyph.h"
 #include "unicodeLatinMap.h"
 #include "pandaSystem.h"
 
@@ -167,7 +168,10 @@ init_libtext() {
   DynamicTextFont::init_type();
   DynamicTextPage::init_type();
   GeomTextGlyph::init_type();
+  qpGeomTextGlyph::init_type();
+
   GeomTextGlyph::register_with_read_factory();
+  qpGeomTextGlyph::register_with_read_factory();
 
   PandaSystem *ps = PandaSystem::get_global_ptr();
   ps->add_system("Freetype");

+ 78 - 33
panda/src/text/dynamicTextGlyph.cxx

@@ -22,9 +22,15 @@
 
 #include "dynamicTextPage.h"
 #include "geomTextGlyph.h"
+#include "qpgeomTextGlyph.h"
+#include "qpgeomVertexData.h"
+#include "qpgeomVertexFormat.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 #include "textureAttrib.h"
 #include "transparencyAttrib.h"
 #include "renderState.h"
+#include "config_gobj.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: DynamicTextGlyph::Destructor
@@ -116,40 +122,79 @@ make_geom(int bitmap_top, int bitmap_left, float advance, float poly_margin,
   float uv_left = (float)(_x - poly_margin) / _page->get_x_size();
   float uv_bottom = 1.0f - (float)(_y + poly_margin + tex_y_size) / _page->get_y_size();
   float uv_right = (float)(_x + poly_margin + tex_x_size) / _page->get_x_size();
-
   // Create a corresponding tristrip.
-  PT(Geom) geom = new GeomTextGlyph(this);
-  _geom = geom;
-
-  // The above will increment our _geom_count to 1.  Reset it back
-  // down to 0, since our own internal Geom doesn't count.
-  nassertv(_geom_count == 1);
-  _geom_count--;
-
-  PTA_Vertexf coords;
-  coords.push_back(Vertexf(left, 0, top));
-  coords.push_back(Vertexf(left, 0, bottom));
-  coords.push_back(Vertexf(right, 0, top));
-  coords.push_back(Vertexf(right, 0, bottom));
-
-  PTA_TexCoordf texcoords;
-  texcoords.push_back(TexCoordf(uv_left, uv_top));
-  texcoords.push_back(TexCoordf(uv_left, uv_bottom));
-  texcoords.push_back(TexCoordf(uv_right, uv_top));
-  texcoords.push_back(TexCoordf(uv_right, uv_bottom));
-
-  PTA_Colorf colors;
-  colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-
-  PTA_int lengths;
-  lengths.push_back(4);
-
-  geom->set_coords(coords);
-  geom->set_texcoords(texcoords, G_PER_VERTEX);
-  geom->set_colors(colors, G_OVERALL);
-  geom->set_lengths(lengths);
-  geom->set_num_prims(1);
-
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      (string(), qpGeomVertexFormat::get_v3cpt2(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+    qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+    vertex.add_data3f(left, 0, top);
+    vertex.add_data3f(left, 0, bottom);
+    vertex.add_data3f(right, 0, top);
+    vertex.add_data3f(right, 0, bottom);
+
+    color.add_data4f(1.0f, 1.0f, 1.0f, 1.0f);
+    color.add_data4f(1.0f, 1.0f, 1.0f, 1.0f);
+    color.add_data4f(1.0f, 1.0f, 1.0f, 1.0f);
+    color.add_data4f(1.0f, 1.0f, 1.0f, 1.0f);
+    
+    texcoord.add_data2f(uv_left, uv_top);
+    texcoord.add_data2f(uv_left, uv_bottom);
+    texcoord.add_data2f(uv_right, uv_top);
+    texcoord.add_data2f(uv_right, uv_bottom);
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    strip->add_consecutive_vertices(0, 4);
+    strip->close_primitive();
+    
+    PT(qpGeom) geom = new qpGeomTextGlyph(this);
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+    
+    _geom = geom;
+    
+    // The above will increment our _geom_count to 1.  Reset it back
+    // down to 0, since our own internal Geom doesn't count.
+    nassertv(_geom_count == 1);
+    _geom_count--;
+
+  } else {
+    PT(Geom) geom = new GeomTextGlyph(this);
+    _geom = geom;
+    
+    // The above will increment our _geom_count to 1.  Reset it back
+    // down to 0, since our own internal Geom doesn't count.
+    nassertv(_geom_count == 1);
+    _geom_count--;
+    
+    PTA_Vertexf coords;
+    coords.push_back(Vertexf(left, 0, top));
+    coords.push_back(Vertexf(left, 0, bottom));
+    coords.push_back(Vertexf(right, 0, top));
+    coords.push_back(Vertexf(right, 0, bottom));
+    
+    PTA_TexCoordf texcoords;
+    texcoords.push_back(TexCoordf(uv_left, uv_top));
+    texcoords.push_back(TexCoordf(uv_left, uv_bottom));
+    texcoords.push_back(TexCoordf(uv_right, uv_top));
+    texcoords.push_back(TexCoordf(uv_right, uv_bottom));
+    
+    PTA_Colorf colors;
+    colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+    
+    PTA_int lengths;
+    lengths.push_back(4);
+    
+    geom->set_coords(coords);
+    geom->set_texcoords(texcoords, G_PER_VERTEX);
+    geom->set_colors(colors, G_OVERALL);
+    geom->set_lengths(lengths);
+    geom->set_num_prims(1);
+  }
+    
   _state = RenderState::make(TextureAttrib::make(_page),
                              TransparencyAttrib::make(TransparencyAttrib::M_alpha));
 

+ 47 - 0
panda/src/text/qpgeomTextGlyph.I

@@ -0,0 +1,47 @@
+// Filename: qpgeomTextGlyph.I
+// Created by:  drose (31Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: qpGeomTextGlyph::Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomTextGlyph::
+qpGeomTextGlyph(DynamicTextGlyph *glyph) :
+  _glyph(glyph)
+{
+  if (_glyph != (DynamicTextGlyph *)NULL) {
+    _glyph->_geom_count++;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTextGlyph::Copy Constructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE qpGeomTextGlyph::
+qpGeomTextGlyph(const qpGeomTextGlyph &copy) :
+  qpGeom(copy),
+  _glyph(copy._glyph)
+{
+  if (_glyph != (DynamicTextGlyph *)NULL) {
+    _glyph->_geom_count++;
+  }
+}

+ 101 - 0
panda/src/text/qpgeomTextGlyph.cxx

@@ -0,0 +1,101 @@
+// Filename: qpgeomTextGlyph.cxx
+// Created by:  drose (31Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 "geomTextGlyph.h"
+
+#ifdef HAVE_FREETYPE
+
+#include "datagramIterator.h"
+#include "bamReader.h"
+
+TypeHandle qpGeomTextGlyph::_type_handle;
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTextGlyph::Copy Assignment Operator
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void qpGeomTextGlyph::
+operator = (const qpGeomTextGlyph &copy) {
+  qpGeom::operator = (copy);
+  if (_glyph != copy._glyph) {
+    if (_glyph != (DynamicTextGlyph *)NULL) {
+      _glyph->_geom_count--;
+    }
+    _glyph = copy._glyph;
+    if (_glyph != (DynamicTextGlyph *)NULL) {
+      _glyph->_geom_count++;
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTextGlyph::Destructor
+//       Access: Public, Virtual
+//  Description: 
+////////////////////////////////////////////////////////////////////
+qpGeomTextGlyph::
+~qpGeomTextGlyph() {
+  if (_glyph != (DynamicTextGlyph *)NULL) {
+    _glyph->_geom_count--;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTextGlyph::make_copy
+//       Access: Public, Virtual
+//  Description: Returns a newly-allocated qpGeom that is a shallow copy
+//               of this one.  It will be a different qpGeom pointer,
+//               but its internal data may or may not be shared with
+//               that of the original qpGeom.
+////////////////////////////////////////////////////////////////////
+qpGeom *qpGeomTextGlyph::
+make_copy() const {
+  return new qpGeomTextGlyph(*this);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTextGlyph::register_with_factory
+//       Access: Public, Static
+//  Description: Factory method to generate a qpGeomTextGlyph object
+////////////////////////////////////////////////////////////////////
+void qpGeomTextGlyph::
+register_with_read_factory() {
+  BamReader::get_factory()->register_factory(get_class_type(), make_qpGeomTextGlyph);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomTextGlyph::make_qpGeomTextGlyph
+//       Access: Public
+//  Description: Factory method to generate a qpGeomTextGlyph object
+////////////////////////////////////////////////////////////////////
+TypedWritable* qpGeomTextGlyph::
+make_qpGeomTextGlyph(const FactoryParams &params) {
+  qpGeomTextGlyph *me = new qpGeomTextGlyph((DynamicTextGlyph *)NULL);
+  DatagramIterator scan;
+  BamReader *manager;
+
+  parse_params(params, scan, manager);
+  me->fillin(scan, manager);
+  me->make_dirty();
+  me->config();
+  return me;
+}
+
+#endif  // HAVE_FREETYPE

+ 77 - 0
panda/src/text/qpgeomTextGlyph.h

@@ -0,0 +1,77 @@
+// Filename: qpgeomTextGlyph.h
+// Created by:  drose (31Mar05)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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 qpGEOMTEXTGLYPH_H
+#define qpGEOMTEXTGLYPH_H
+
+#include "pandabase.h"
+
+#ifdef HAVE_FREETYPE
+
+#include "qpgeom.h"
+#include "dynamicTextGlyph.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : qpGeomTextGlyph
+// Description : This is a specialization on Geom for containing a
+//               triangle strip intended to represent a
+//               DynamicTextGlyph.  Its sole purpose is to maintain
+//               the geom count on the glyph, so we can determine the
+//               actual usage count on a dynamic glyph (and thus know
+//               when it is safe to recycle the glyph).
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA qpGeomTextGlyph : public qpGeom {
+public:
+  INLINE qpGeomTextGlyph(DynamicTextGlyph *glyph);
+  INLINE qpGeomTextGlyph(const qpGeomTextGlyph &copy);
+  void operator = (const qpGeomTextGlyph &copy);
+  virtual ~qpGeomTextGlyph();
+
+  virtual qpGeom *make_copy() const;
+
+private:
+  PT(DynamicTextGlyph) _glyph;
+
+public:
+  static void register_with_read_factory();
+  static TypedWritable *make_qpGeomTextGlyph(const FactoryParams &params);
+
+PUBLISHED:
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+public:
+  static void init_type() {
+    qpGeom::init_type();
+    register_type(_type_handle, "qpGeomTextGlyph",
+                  qpGeom::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 "qpgeomTextGlyph.I"
+
+#endif  // HAVE_FREETYPE
+
+#endif // GEOMTEXTGLYPH_H

+ 57 - 17
panda/src/text/staticTextFont.cxx

@@ -22,6 +22,8 @@
 #include "geom.h"
 #include "geomPoint.h"
 #include "geomNode.h"
+#include "qpgeomVertexReader.h"
+#include "qpgeomPoints.h"
 #include "renderState.h"
 #include "dcast.h"
 
@@ -184,7 +186,8 @@ get_glyph(int character, const TextGlyph *&glyph) {
 //               those two Geoms.
 ////////////////////////////////////////////////////////////////////
 void StaticTextFont::
-find_character_gsets(PandaNode *root, const Geom *&ch, const GeomPoint *&dot,
+find_character_gsets(PandaNode *root, CPT(Geom) &ch, 
+                     const GeomPoint *&dot1, CPT(qpGeom) &dot2,
                      const RenderState *&state, const RenderState *net_state) {
   CPT(RenderState) next_net_state = net_state->compose(root->get_state());
 
@@ -193,11 +196,29 @@ find_character_gsets(PandaNode *root, const Geom *&ch, const GeomPoint *&dot,
 
     for (int i = 0; i < geode->get_num_geoms(); i++) {
       const Geom *geom = geode->get_geom(i);
-      if (geom->is_of_type(GeomPoint::get_class_type())) {
-        dot = DCAST(GeomPoint, geom);
+      if (geom->is_of_type(qpGeom::get_class_type())) {
+        CPT(qpGeom) qpgeom = DCAST(qpGeom, geom);
 
-      } else if (geom->is_of_type(Geom::get_class_type())) {
-        ch = DCAST(Geom, geom);
+        bool found_points = false;
+        for (int j = 0; j < qpgeom->get_num_primitives() && !found_points; j++) {
+          const qpGeomPrimitive *primitive = qpgeom->get_primitive(j);
+          if (primitive->is_of_type(qpGeomPoints::get_class_type())) {
+            dot2 = qpgeom;
+            found_points = true;
+          }
+        }
+        if (!found_points) {
+          // If it doesn't have any points, it must be the regular
+          // letter.
+          ch = geom;
+          state = next_net_state->compose(geode->get_geom_state(i));
+        }
+
+      } else if (geom->is_of_type(GeomPoint::get_class_type())) {
+        dot1 = DCAST(GeomPoint, geom);
+
+      } else {
+        ch = geom;
         state = next_net_state->compose(geode->get_geom_state(i));
       }
     }
@@ -206,7 +227,8 @@ find_character_gsets(PandaNode *root, const Geom *&ch, const GeomPoint *&dot,
     PandaNode::Children cr = root->get_children();
     int num_children = cr.get_num_children();
     for (int i = 0; i < num_children; i++) {
-      find_character_gsets(cr.get_child(i), ch, dot, state, next_net_state);
+      find_character_gsets(cr.get_child(i), ch, dot1, dot2, state,
+                           next_net_state);
     }
   }
 }
@@ -236,46 +258,64 @@ find_characters(PandaNode *root, const RenderState *net_state) {
 
   if (all_digits) {
     int character = atoi(name.c_str());
-    const Geom *ch = NULL;
-    const GeomPoint *dot = NULL;
+    CPT(Geom) ch;
+    const GeomPoint *dot1 = NULL;
+    CPT(qpGeom) dot2;
     const RenderState *state = NULL;
-    find_character_gsets(root, ch, dot, state, next_net_state);
-    if (dot != NULL) {
+    find_character_gsets(root, ch, dot1, dot2, state, next_net_state);
+    if (dot1 != NULL) {
       // Get the first vertex from the "dot" geoset.  This will be the
       // origin of the next character.
       PTA_Vertexf alist;
       PTA_ushort ilist;
       float width;
-      dot->get_coords(alist, ilist);
+      dot1->get_coords(alist, ilist);
       if (ilist.empty()) {
         width = alist[0][0];
       } else {
         width = alist[ilist[0]][0];
       }
 
+      _glyphs[character] = new TextGlyph(ch, state, width);
+
+    } else if (ch != (Geom *)NULL && dot2 != (qpGeom *)NULL) {
+      // Get the first vertex from the "dot" geoset.  This will be the
+      // origin of the next character.
+      qpGeomVertexReader reader(dot2->get_vertex_data(), InternalName::get_vertex());
+      float width = reader.get_data1f();
+
       _glyphs[character] = new TextGlyph(ch, state, width);
     }
 
   } else if (name == "ds") {
-    // The group "ds" is a special node that indicate's the font's
+    // The group "ds" is a special node that indicates the font's
     // design size, or line height.
 
-    const Geom *ch = NULL;
-    const GeomPoint *dot = NULL;
+    CPT(Geom) ch;
+    const GeomPoint *dot1 = NULL;
+    CPT(qpGeom) dot2;
     const RenderState *state = NULL;
-    find_character_gsets(root, ch, dot, state, next_net_state);
-    if (dot != NULL) {
+    find_character_gsets(root, ch, dot1, dot2, state, next_net_state);
+    if (dot1 != NULL) {
       // Get the first vertex from the "dot" geoset.  This will be the
       // design size indicator.
       PTA_Vertexf alist;
       PTA_ushort ilist;
-      dot->get_coords(alist, ilist);
+      dot1->get_coords(alist, ilist);
       if (ilist.empty()) {
         _line_height = alist[0][2];
       } else {
         _line_height = alist[ilist[0]][2];
       }
       _space_advance = 0.25f * _line_height;
+
+    } else if (ch != (Geom *)NULL && dot2 != (qpGeom *)NULL) {
+      // Get the first vertex from the "dot" geoset.  This will be the
+      // design size indicator.
+      const qpGeom *qpgeom = DCAST(qpGeom, ch);
+      qpGeomVertexReader reader(qpgeom->get_vertex_data(), InternalName::get_vertex());
+      _line_height = reader.get_data3f()[2];
+      _space_advance = 0.25f * _line_height;
     }
 
   } else {

+ 5 - 3
panda/src/text/staticTextFont.h

@@ -25,11 +25,12 @@
 #include "textFont.h"
 #include "textGlyph.h"
 #include "pandaNode.h"
+#include "geom.h"
+#include "qpgeom.h"
 #include "pointerTo.h"
 #include "pmap.h"
 
 class Node;
-class Geom;
 class GeomPoint;
 
 ////////////////////////////////////////////////////////////////////
@@ -50,8 +51,9 @@ public:
   virtual bool get_glyph(int character, const TextGlyph *&glyph);
 
 private:
-  void find_character_gsets(PandaNode *root, const Geom *&ch, 
-                            const GeomPoint *&dot,
+  void find_character_gsets(PandaNode *root, CPT(Geom) &ch, 
+                            const GeomPoint *&dot1,
+                            CPT(qpGeom) &dot2,
                             const RenderState *&state, 
                             const RenderState *net_state);
   void find_characters(PandaNode *root,

+ 2 - 0
panda/src/text/textNode.I

@@ -407,6 +407,7 @@ get_frame_actual() const {
 INLINE void TextNode::
 set_frame_line_width(float frame_width) {
   _frame_width = frame_width;
+  invalidate_no_measure();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -435,6 +436,7 @@ set_frame_corners(bool corners) {
   } else {
     _flags &= ~F_frame_corners;
   }
+  invalidate_no_measure();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 288 - 140
panda/src/text/textNode.cxx

@@ -27,6 +27,11 @@
 #include "geomTristrip.h"
 #include "geomLinestrip.h"
 #include "geomPoint.h"
+#include "qpgeom.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomPoints.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 #include "geomNode.h"
 #include "notify.h"
 #include "transformState.h"
@@ -589,42 +594,74 @@ do_measure() {
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) TextNode::
 make_frame() {
-  PT(GeomNode) frame_geode = new GeomNode("frame");
+  PT(GeomNode) frame_node = new GeomNode("frame");
 
   LVector4f dimensions = get_frame_actual();
   float left = dimensions[0];
   float right = dimensions[1];
   float bottom = dimensions[2];
   float top = dimensions[3];
-
-  GeomLinestrip *geoset = new GeomLinestrip;
-  PTA_int lengths=PTA_int::empty_array(0);
-  PTA_Vertexf verts;
-  lengths.push_back(5);
-  verts.push_back(Vertexf(left, 0.0f, top));
-  verts.push_back(Vertexf(left, 0.0f, bottom));
-  verts.push_back(Vertexf(right, 0.0f, bottom));
-  verts.push_back(Vertexf(right, 0.0f, top));
-  verts.push_back(Vertexf(left, 0.0f, top));
-
+    
   CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _frame_width);
   CPT(RenderState) state = RenderState::make(thick);
 
-  geoset->set_num_prims(1);
-  geoset->set_lengths(lengths);
-
-  geoset->set_coords(verts);
-  frame_geode->add_geom(geoset, state);
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("text", qpGeomVertexFormat::get_v3cp(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+
+    vertex.add_data3f(left, 0.0f, top);
+    vertex.add_data3f(left, 0.0f, bottom);
+    vertex.add_data3f(right, 0.0f, bottom);
+    vertex.add_data3f(right, 0.0f, top);
+    
+    PT(qpGeomLinestrips) frame = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+    frame->add_consecutive_vertices(0, 4);
+    frame->add_vertex(0);
+    frame->close_primitive();
+    
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(frame);
+    frame_node->add_geom(geom, state);
+
+    if (get_frame_corners()) {
+      PT(qpGeomPoints) corners = new qpGeomPoints(qpGeomUsageHint::UH_static);
+      corners->add_consecutive_vertices(0, 4);
+      PT(qpGeom) geom2 = new qpGeom;
+      geom2->set_vertex_data(vdata);
+      geom2->add_primitive(corners);
+      frame_node->add_geom(geom2, state);
+    }
 
-  if (get_frame_corners()) {
-    GeomPoint *geoset = new GeomPoint;
+  } else {
+    GeomLinestrip *geoset = new GeomLinestrip;
+    PTA_int lengths=PTA_int::empty_array(0);
+    PTA_Vertexf verts;
+    lengths.push_back(5);
+    verts.push_back(Vertexf(left, 0.0f, top));
+    verts.push_back(Vertexf(left, 0.0f, bottom));
+    verts.push_back(Vertexf(right, 0.0f, bottom));
+    verts.push_back(Vertexf(right, 0.0f, top));
+    verts.push_back(Vertexf(left, 0.0f, top));
+
+    geoset->set_num_prims(1);
+    geoset->set_lengths(lengths);
 
-    geoset->set_num_prims(4);
     geoset->set_coords(verts);
-    frame_geode->add_geom(geoset, state);
+    frame_node->add_geom(geoset, state);
+
+    if (get_frame_corners()) {
+      GeomPoint *geoset = new GeomPoint;
+      
+      geoset->set_num_prims(4);
+      geoset->set_coords(verts);
+      frame_node->add_geom(geoset, state);
+    }
   }
 
-  return frame_geode.p();
+  return frame_node.p();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -634,7 +671,7 @@ make_frame() {
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) TextNode::
 make_card() {
-  PT(GeomNode) card_geode = new GeomNode("card");
+  PT(GeomNode) card_node = new GeomNode("card");
 
   LVector4f dimensions = get_card_actual();
   float left = dimensions[0];
@@ -642,34 +679,63 @@ make_card() {
   float bottom = dimensions[2];
   float top = dimensions[3];
 
-  GeomTristrip *geoset = new GeomTristrip;
-  PTA_int lengths=PTA_int::empty_array(0);
-  lengths.push_back(4);
-
-  PTA_Vertexf verts;
-  verts.push_back(Vertexf(left, 0.02f, top));
-  verts.push_back(Vertexf(left, 0.02f, bottom));
-  verts.push_back(Vertexf(right, 0.02f, top));
-  verts.push_back(Vertexf(right, 0.02f, bottom));
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("text", qpGeomVertexFormat::get_v3cpt2(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+    vertex.add_data3f(left, 0.0f, top);
+    vertex.add_data3f(left, 0.0f, bottom);
+    vertex.add_data3f(right, 0.0f, top);
+    vertex.add_data3f(right, 0.0f, bottom);
+
+    texcoord.add_data2f(0.0f, 1.0f);
+    texcoord.add_data2f(0.0f, 0.0f);
+    texcoord.add_data2f(1.0f, 1.0f);
+    texcoord.add_data2f(1.0f, 0.0f);
+    
+    PT(qpGeomTristrips) card = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    card->add_consecutive_vertices(0, 4);
+    card->close_primitive();
+    
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(card);
+
+    card_node->add_geom(geom);
 
-  geoset->set_num_prims(1);
-  geoset->set_lengths(lengths);
+  } else {
+    GeomTristrip *geoset = new GeomTristrip;
+    PTA_int lengths=PTA_int::empty_array(0);
+    lengths.push_back(4);
+
+    PTA_Vertexf verts;
+    verts.push_back(Vertexf(left, 0.02f, top));
+    verts.push_back(Vertexf(left, 0.02f, bottom));
+    verts.push_back(Vertexf(right, 0.02f, top));
+    verts.push_back(Vertexf(right, 0.02f, bottom));
+    
+    geoset->set_num_prims(1);
+    geoset->set_lengths(lengths);
 
-  geoset->set_coords(verts);
+    geoset->set_coords(verts);
 
-  if (has_card_texture()) {
-    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));
+    if (has_card_texture()) {
+      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);
+    }
 
-    geoset->set_texcoords(uvs, G_PER_VERTEX);
+    card_node->add_geom(geoset);
   }
 
-  card_geode->add_geom(geoset);
-
-  return card_geode.p();
+  return card_node.p();
 }
 
 
@@ -681,7 +747,7 @@ make_card() {
 ////////////////////////////////////////////////////////////////////
 PT(PandaNode) TextNode::
 make_card_with_border() {
-  PT(GeomNode) card_geode = new GeomNode("card");
+  PT(GeomNode) card_node = new GeomNode("card");
 
   LVector4f dimensions = get_card_actual();
   float left = dimensions[0];
@@ -697,103 +763,185 @@ make_card_with_border() {
   //  9 11          13 15 \  /
   // 10 12          14 16 - three
   //
-  GeomTristrip *geoset = new GeomTristrip;
-  PTA_int lengths;
-  lengths.push_back(8);
-  lengths.push_back(8);
-  lengths.push_back(8);
-
-  PTA_Vertexf verts;
-  // verts 1,2,3,4
-  verts.push_back(Vertexf(left, 0.02f, top));
-  verts.push_back(Vertexf(left, 0.02f, top - _card_border_size));
-  verts.push_back(Vertexf(left + _card_border_size, 0.02f, top));
-  verts.push_back(Vertexf(left + _card_border_size, 0.02f,
-                          top - _card_border_size));
-  // verts 5,6,7,8
-  verts.push_back(Vertexf(right - _card_border_size, 0.02f, top));
-  verts.push_back(Vertexf(right - _card_border_size, 0.02f,
-                          top - _card_border_size));
-  verts.push_back(Vertexf(right, 0.02f, top));
-  verts.push_back(Vertexf(right, 0.02f, top - _card_border_size));
-  // verts 9,10,11,12
-  verts.push_back(Vertexf(left, 0.02f, bottom + _card_border_size));
-  verts.push_back(Vertexf(left, 0.02f, bottom));
-  verts.push_back(Vertexf(left + _card_border_size, 0.02f,
-                          bottom + _card_border_size));
-  verts.push_back(Vertexf(left + _card_border_size, 0.02f, bottom));
-  // verts 13,14,15,16
-  verts.push_back(Vertexf(right - _card_border_size, 0.02f,
-                          bottom + _card_border_size));
-  verts.push_back(Vertexf(right - _card_border_size, 0.02f, bottom));
-  verts.push_back(Vertexf(right, 0.02f, bottom + _card_border_size));
-  verts.push_back(Vertexf(right, 0.02f, bottom));
-
-  PTA_ushort indices;
-  // tristrip #1
-  indices.push_back(0);
-  indices.push_back(1);
-  indices.push_back(2);
-  indices.push_back(3);
-  indices.push_back(4);
-  indices.push_back(5);
-  indices.push_back(6);
-  indices.push_back(7);
-  // tristrip #2
-  indices.push_back(1);
-  indices.push_back(8);
-  indices.push_back(3);
-  indices.push_back(10);
-  indices.push_back(5);
-  indices.push_back(12);
-  indices.push_back(7);
-  indices.push_back(14);
-  // tristrip #3
-  indices.push_back(8);
-  indices.push_back(9);
-  indices.push_back(10);
-  indices.push_back(11);
-  indices.push_back(12);
-  indices.push_back(13);
-  indices.push_back(14);
-  indices.push_back(15);
-
-  geoset->set_num_prims(3);
-  geoset->set_lengths(lengths);
-
-  geoset->set_coords(verts,indices);
-
-  if (has_card_texture()) {
-    PTA_TexCoordf uvs;
-    uvs.push_back(TexCoordf(0.0f, 1.0f)); //1
-    uvs.push_back(TexCoordf(0.0f, 1.0f - _card_border_uv_portion)); //2
-    uvs.push_back(TexCoordf(0.0f + _card_border_uv_portion, 1.0f)); //3
-    uvs.push_back(TexCoordf(0.0f + _card_border_uv_portion,
-      1.0f - _card_border_uv_portion)); //4
-    uvs.push_back(TexCoordf( 1.0f -_card_border_uv_portion, 1.0f)); //5
-    uvs.push_back(TexCoordf( 1.0f -_card_border_uv_portion,
-      1.0f - _card_border_uv_portion)); //6
-    uvs.push_back(TexCoordf(1.0f, 1.0f)); //7
-    uvs.push_back(TexCoordf(1.0f, 1.0f - _card_border_uv_portion)); //8
-
-    uvs.push_back(TexCoordf(0.0f, _card_border_uv_portion)); //9
-    uvs.push_back(TexCoordf(0.0f, 0.0f)); //10
-    uvs.push_back(TexCoordf(_card_border_uv_portion, _card_border_uv_portion)); //11
-    uvs.push_back(TexCoordf(_card_border_uv_portion, 0.0f)); //12
-
-    uvs.push_back(TexCoordf(1.0f - _card_border_uv_portion, _card_border_uv_portion));//13
-    uvs.push_back(TexCoordf(1.0f - _card_border_uv_portion, 0.0f));//14
-    uvs.push_back(TexCoordf(1.0f, _card_border_uv_portion));//15
-    uvs.push_back(TexCoordf(1.0f, 0.0f));//16
-
-    // we can use same ref's as before (same order)
-    geoset->set_texcoords(uvs, G_PER_VERTEX, indices);
 
-  }
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("text", qpGeomVertexFormat::get_v3cpt2(),
+       qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+    // verts 1,2,3,4
+    vertex.add_data3f(left, 0.02f, top);
+    vertex.add_data3f(left, 0.02f, top - _card_border_size);
+    vertex.add_data3f(left + _card_border_size, 0.02f, top);
+    vertex.add_data3f(left + _card_border_size, 0.02f,
+                      top - _card_border_size);
+    // verts 5,6,7,8
+    vertex.add_data3f(right - _card_border_size, 0.02f, top);
+    vertex.add_data3f(right - _card_border_size, 0.02f,
+                      top - _card_border_size);
+    vertex.add_data3f(right, 0.02f, top);
+    vertex.add_data3f(right, 0.02f, top - _card_border_size);
+    // verts 9,10,11,12
+    vertex.add_data3f(left, 0.02f, bottom + _card_border_size);
+    vertex.add_data3f(left, 0.02f, bottom);
+    vertex.add_data3f(left + _card_border_size, 0.02f,
+                      bottom + _card_border_size);
+    vertex.add_data3f(left + _card_border_size, 0.02f, bottom);
+    // verts 13,14,15,16
+    vertex.add_data3f(right - _card_border_size, 0.02f,
+                      bottom + _card_border_size);
+    vertex.add_data3f(right - _card_border_size, 0.02f, bottom);
+    vertex.add_data3f(right, 0.02f, bottom + _card_border_size);
+    vertex.add_data3f(right, 0.02f, bottom);
+
+    texcoord.add_data2f(0.0f, 1.0f); //1
+    texcoord.add_data2f(0.0f, 1.0f - _card_border_uv_portion); //2
+    texcoord.add_data2f(0.0f + _card_border_uv_portion, 1.0f); //3
+    texcoord.add_data2f(0.0f + _card_border_uv_portion,
+                        1.0f - _card_border_uv_portion); //4
+    texcoord.add_data2f(1.0f -_card_border_uv_portion, 1.0f); //5
+    texcoord.add_data2f(1.0f -_card_border_uv_portion,
+                        1.0f - _card_border_uv_portion); //6
+    texcoord.add_data2f(1.0f, 1.0f); //7
+    texcoord.add_data2f(1.0f, 1.0f - _card_border_uv_portion); //8
+
+    texcoord.add_data2f(0.0f, _card_border_uv_portion); //9
+    texcoord.add_data2f(0.0f, 0.0f); //10
+    texcoord.add_data2f(_card_border_uv_portion, _card_border_uv_portion); //11
+    texcoord.add_data2f(_card_border_uv_portion, 0.0f); //12
+
+    texcoord.add_data2f(1.0f - _card_border_uv_portion, _card_border_uv_portion);//13
+    texcoord.add_data2f(1.0f - _card_border_uv_portion, 0.0f);//14
+    texcoord.add_data2f(1.0f, _card_border_uv_portion);//15
+    texcoord.add_data2f(1.0f, 0.0f);//16
+    
+    PT(qpGeomTristrips) card = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+
+    // tristrip #1
+    card->add_consecutive_vertices(0, 8);
+    card->close_primitive();
+
+    // tristrip #2
+    card->add_vertex(1);
+    card->add_vertex(8);
+    card->add_vertex(3);
+    card->add_vertex(10);
+    card->add_vertex(5);
+    card->add_vertex(12);
+    card->add_vertex(7);
+    card->add_vertex(14);
+    card->close_primitive();
+
+    // tristrip #3
+    card->add_consecutive_vertices(8, 8);
+    card->close_primitive();
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(card);
+
+    card_node->add_geom(geom);
 
-  card_geode->add_geom(geoset);
+  } else {
+    GeomTristrip *geoset = new GeomTristrip;
+    PTA_int lengths;
+    lengths.push_back(8);
+    lengths.push_back(8);
+    lengths.push_back(8);
+    
+    PTA_Vertexf verts;
+    // verts 1,2,3,4
+    verts.push_back(Vertexf(left, 0.02f, top));
+    verts.push_back(Vertexf(left, 0.02f, top - _card_border_size));
+    verts.push_back(Vertexf(left + _card_border_size, 0.02f, top));
+    verts.push_back(Vertexf(left + _card_border_size, 0.02f,
+                            top - _card_border_size));
+    // verts 5,6,7,8
+    verts.push_back(Vertexf(right - _card_border_size, 0.02f, top));
+    verts.push_back(Vertexf(right - _card_border_size, 0.02f,
+                            top - _card_border_size));
+    verts.push_back(Vertexf(right, 0.02f, top));
+    verts.push_back(Vertexf(right, 0.02f, top - _card_border_size));
+    // verts 9,10,11,12
+    verts.push_back(Vertexf(left, 0.02f, bottom + _card_border_size));
+    verts.push_back(Vertexf(left, 0.02f, bottom));
+    verts.push_back(Vertexf(left + _card_border_size, 0.02f,
+                            bottom + _card_border_size));
+    verts.push_back(Vertexf(left + _card_border_size, 0.02f, bottom));
+    // verts 13,14,15,16
+    verts.push_back(Vertexf(right - _card_border_size, 0.02f,
+                            bottom + _card_border_size));
+    verts.push_back(Vertexf(right - _card_border_size, 0.02f, bottom));
+    verts.push_back(Vertexf(right, 0.02f, bottom + _card_border_size));
+    verts.push_back(Vertexf(right, 0.02f, bottom));
+    
+    PTA_ushort indices;
+    // tristrip #1
+    indices.push_back(0);
+    indices.push_back(1);
+    indices.push_back(2);
+    indices.push_back(3);
+    indices.push_back(4);
+    indices.push_back(5);
+    indices.push_back(6);
+    indices.push_back(7);
+    // tristrip #2
+    indices.push_back(1);
+    indices.push_back(8);
+    indices.push_back(3);
+    indices.push_back(10);
+    indices.push_back(5);
+    indices.push_back(12);
+    indices.push_back(7);
+    indices.push_back(14);
+    // tristrip #3
+    indices.push_back(8);
+    indices.push_back(9);
+    indices.push_back(10);
+    indices.push_back(11);
+    indices.push_back(12);
+    indices.push_back(13);
+    indices.push_back(14);
+    indices.push_back(15);
+    
+    geoset->set_num_prims(3);
+    geoset->set_lengths(lengths);
+    
+    geoset->set_coords(verts,indices);
+    
+    if (has_card_texture()) {
+      PTA_TexCoordf uvs;
+      uvs.push_back(TexCoordf(0.0f, 1.0f)); //1
+      uvs.push_back(TexCoordf(0.0f, 1.0f - _card_border_uv_portion)); //2
+      uvs.push_back(TexCoordf(0.0f + _card_border_uv_portion, 1.0f)); //3
+      uvs.push_back(TexCoordf(0.0f + _card_border_uv_portion,
+                              1.0f - _card_border_uv_portion)); //4
+      uvs.push_back(TexCoordf( 1.0f -_card_border_uv_portion, 1.0f)); //5
+      uvs.push_back(TexCoordf( 1.0f -_card_border_uv_portion,
+                               1.0f - _card_border_uv_portion)); //6
+      uvs.push_back(TexCoordf(1.0f, 1.0f)); //7
+      uvs.push_back(TexCoordf(1.0f, 1.0f - _card_border_uv_portion)); //8
+      
+      uvs.push_back(TexCoordf(0.0f, _card_border_uv_portion)); //9
+      uvs.push_back(TexCoordf(0.0f, 0.0f)); //10
+      uvs.push_back(TexCoordf(_card_border_uv_portion, _card_border_uv_portion)); //11
+      uvs.push_back(TexCoordf(_card_border_uv_portion, 0.0f)); //12
+      
+      uvs.push_back(TexCoordf(1.0f - _card_border_uv_portion, _card_border_uv_portion));//13
+      uvs.push_back(TexCoordf(1.0f - _card_border_uv_portion, 0.0f));//14
+      uvs.push_back(TexCoordf(1.0f, _card_border_uv_portion));//15
+      uvs.push_back(TexCoordf(1.0f, 0.0f));//16
+      
+      // we can use same ref's as before (same order)
+      geoset->set_texcoords(uvs, G_PER_VERTEX, indices);
+    }
+
+    card_node->add_geom(geoset);
+  }
 
-  return card_geode.p();
+  return card_node.p();
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/text/textProperties.cxx

@@ -278,7 +278,7 @@ load_default_font() {
   if (!text_default_font.empty()) {
     // First, attempt to load the user-specified filename.
     _default_font = FontPool::load_font(text_default_font.get_value());
-    if (_default_font->is_valid()) {
+    if (_default_font != (TextFont *)NULL && _default_font->is_valid()) {
       return;
     }
   }

+ 1 - 0
panda/src/text/text_composite1.cxx

@@ -5,4 +5,5 @@
 #include "dynamicTextPage.cxx"
 #include "fontPool.cxx"
 #include "geomTextGlyph.cxx"
+#include "qpgeomTextGlyph.cxx"
 #include "staticTextFont.cxx"