Browse Source

handle use_qpgeom on more internal things

David Rose 21 năm trước cách đây
mục cha
commit
20e9703887
45 tập tin đã thay đổi với 1566 bổ sung594 xóa
  1. 1 1
      panda/src/collide/collisionInvSphere.cxx
  2. 1 1
      panda/src/collide/collisionPlane.cxx
  3. 1 1
      panda/src/collide/collisionPolygon.cxx
  4. 1 1
      panda/src/collide/collisionSphere.cxx
  5. 1 1
      panda/src/collide/collisionTube.cxx
  6. 255 123
      panda/src/distort/projectionScreen.cxx
  7. 22 0
      panda/src/egg/eggVertexPool.cxx
  8. 1 0
      panda/src/egg/eggVertexPool.h
  9. 14 1
      panda/src/egg2pg/eggBinner.cxx
  10. 2 0
      panda/src/egg2pg/eggBinner.h
  11. 29 11
      panda/src/egg2pg/eggLoader.cxx
  12. 1 1
      panda/src/framework/windowFramework.cxx
  13. 4 0
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  14. 11 0
      panda/src/gobj/geom.cxx
  15. 1 0
      panda/src/gobj/geom.h
  16. 209 55
      panda/src/gobj/lens.cxx
  17. 4 0
      panda/src/gobj/lens.h
  18. 0 34
      panda/src/gobj/qpgeom.I
  19. 91 1
      panda/src/gobj/qpgeom.cxx
  20. 8 1
      panda/src/gobj/qpgeom.h
  21. 11 0
      panda/src/gobj/qpgeomLines.cxx
  22. 1 0
      panda/src/gobj/qpgeomLines.h
  23. 11 0
      panda/src/gobj/qpgeomLinestrips.cxx
  24. 2 0
      panda/src/gobj/qpgeomLinestrips.h
  25. 11 0
      panda/src/gobj/qpgeomPoints.cxx
  26. 1 0
      panda/src/gobj/qpgeomPoints.h
  27. 13 0
      panda/src/gobj/qpgeomPrimitive.cxx
  28. 2 0
      panda/src/gobj/qpgeomPrimitive.h
  29. 6 0
      panda/src/gobj/qpgeomVertexData.cxx
  30. 73 27
      panda/src/grutil/cardMaker.cxx
  31. 5 6
      panda/src/grutil/lineSegs.I
  32. 123 64
      panda/src/grutil/lineSegs.cxx
  33. 4 2
      panda/src/grutil/lineSegs.h
  34. 70 17
      panda/src/grutil/multitexReducer.cxx
  35. 4 0
      panda/src/parametrics/ropeNode.cxx
  36. 130 61
      panda/src/parametrics/sheetNode.cxx
  37. 63 9
      panda/src/pgraph/cullTraverser.cxx
  38. 2 0
      panda/src/pgraph/cullTraverser.h
  39. 0 21
      panda/src/pgraph/geomNode.I
  40. 24 1
      panda/src/pgraph/geomNode.cxx
  41. 1 1
      panda/src/pgraph/geomNode.h
  42. 14 2
      panda/src/pgraph/geomTransformer.cxx
  43. 334 141
      panda/src/pgui/pgFrameStyle.cxx
  44. 1 7
      panda/src/text/dynamicTextGlyph.cxx
  45. 3 3
      panda/src/text/textNode.cxx

+ 1 - 1
panda/src/collide/collisionInvSphere.cxx

@@ -310,7 +310,7 @@ fill_viz_geom() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("collision", qpGeomVertexFormat::get_v3cp(),
+      ("collision", qpGeomVertexFormat::get_v3(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     

+ 1 - 1
panda/src/collide/collisionPlane.cxx

@@ -327,7 +327,7 @@ fill_viz_geom() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("collision", qpGeomVertexFormat::get_v3cp(),
+      ("collision", qpGeomVertexFormat::get_v3(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
 

+ 1 - 1
panda/src/collide/collisionPolygon.cxx

@@ -819,7 +819,7 @@ draw_polygon(GeomNode *viz_geom_node, GeomNode *bounds_viz_geom_node,
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("collision", qpGeomVertexFormat::get_v3cp(),
+      ("collision", qpGeomVertexFormat::get_v3(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
 

+ 1 - 1
panda/src/collide/collisionSphere.cxx

@@ -329,7 +329,7 @@ fill_viz_geom() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("collision", qpGeomVertexFormat::get_v3cp(),
+      ("collision", qpGeomVertexFormat::get_v3(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     

+ 1 - 1
panda/src/collide/collisionTube.cxx

@@ -393,7 +393,7 @@ fill_viz_geom() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("collision", qpGeomVertexFormat::get_v3cp(),
+      ("collision", qpGeomVertexFormat::get_v3(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     

+ 255 - 123
panda/src/distort/projectionScreen.cxx

@@ -23,6 +23,11 @@
 #include "transformState.h"
 #include "workingNodePath.h"
 #include "switchNode.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
+#include "qpgeomVertexReader.h"
+#include "qpgeomVertexRewriter.h"
 
 TypeHandle ProjectionScreen::_type_handle;
 
@@ -193,88 +198,144 @@ generate_screen(const NodePath &projector, const string &screen_name,
   NodePath this_np(this);
   rel_mat = projector.get_mat(this_np);
 
+  // Create a GeomNode to hold this mesh.
+  PT(GeomNode) geom_node = new GeomNode(screen_name);
+
   // Now compute all the vertices for the screen.  These are arranged
   // in order from left to right and bottom to top.
   int num_verts = num_x_verts * num_y_verts;
   Lens *lens = projector_node->get_lens();
   float t = (distance - lens->get_near()) / (lens->get_far() - lens->get_near());
 
-  PTA_Vertexf coords;
-  PTA_Normalf norms;
-  coords.reserve(num_verts);
   float x_scale = 2.0f / (num_x_verts - 1);
   float y_scale = 2.0f / (num_y_verts - 1);
-  
-  for (int yi = 0; yi < num_y_verts; yi++) {
-    for (int xi = 0; xi < num_x_verts; xi++) {
-      LPoint2f film = LPoint2f((float)xi * x_scale - 1.0f,
-                               (float)yi * y_scale - 1.0f);
-
-      // Reduce the image by the fill ratio.
-      film *= fill_ratio;
-
-      LPoint3f near_point, far_point;
-      lens->extrude(film, near_point, far_point);
-      LPoint3f point = near_point + t * (far_point - near_point);
-
-      // Normals aren't often needed on projection screens, but you
-      // never know.
-      LVector3f normal;
-      lens->extrude_vec(film, normal);
-
-      coords.push_back(point * rel_mat);
-      norms.push_back(-normalize(normal * rel_mat));
+
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("projectionScreen", qpGeomVertexFormat::get_v3n3(),
+       qpGeomUsageHint::UH_dynamic);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter normal(vdata, InternalName::get_normal());
+    
+    for (int yi = 0; yi < num_y_verts; yi++) {
+      for (int xi = 0; xi < num_x_verts; xi++) {
+        LPoint2f film = LPoint2f((float)xi * x_scale - 1.0f,
+                                 (float)yi * y_scale - 1.0f);
+        
+        // Reduce the image by the fill ratio.
+        film *= fill_ratio;
+        
+        LPoint3f near_point, far_point;
+        lens->extrude(film, near_point, far_point);
+        LPoint3f point = near_point + t * (far_point - near_point);
+        
+        // Normals aren't often needed on projection screens, but you
+        // never know.
+        LVector3f norm;
+        lens->extrude_vec(film, norm);
+
+        vertex.add_data3f(point * rel_mat);
+        normal.add_data3f(-normalize(norm * rel_mat));
+      }
     }
-  }
-  nassertr((int)coords.size() == num_verts, NULL);
-
-  // Now synthesize a triangle mesh.  We run triangle strips
-  // horizontally across the grid.
-  int num_tstrips = (num_y_verts-1);
-  int tstrip_length = 2*(num_x_verts-1)+2;
-
-  PTA_int lengths;
-  PTA_ushort vindex;
-
-  // Set the lengths array.  we are creating num_tstrips t-strips,
-  // each of which has tstrip_length vertices.
-  lengths.reserve(num_tstrips);
-  int n;
-  for (n = 0; n < num_tstrips; n++) {
-    lengths.push_back(tstrip_length);
-  }
-  nassertr((int)lengths.size() == num_tstrips, NULL);
-
-  // Now fill up the index array into the vertices.  This lays out the
-  // order of the vertices in each t-strip.
-  vindex.reserve(num_tstrips * tstrip_length);
-  n = 0;
-  int ti, si;
-  for (ti = 1; ti < num_y_verts; ti++) {
-    vindex.push_back(ti * num_x_verts);
-    for (si = 1; si < num_x_verts; si++) {
-      vindex.push_back((ti - 1) * num_x_verts + (si-1));
-      vindex.push_back(ti * num_x_verts + si);
+    nassertr(vdata->get_num_vertices() == num_verts, NULL);
+
+    // Now synthesize a triangle mesh.  We run triangle strips
+    // horizontally across the grid.
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    // Fill up the index array into the vertices.  This lays out the
+    // order of the vertices in each tristrip.
+    int ti, si;
+    for (ti = 1; ti < num_y_verts; ti++) {
+      strip->add_vertex(ti * num_x_verts);
+      for (si = 1; si < num_x_verts; si++) {
+        strip->add_vertex((ti - 1) * num_x_verts + (si-1));
+        strip->add_vertex(ti * num_x_verts + si);
+      }
+      strip->add_vertex((ti - 1) * num_x_verts + (num_x_verts-1));
+      strip->close_primitive();
     }
-    vindex.push_back((ti - 1) * num_x_verts + (num_x_verts-1));
-  }
-  nassertr((int)vindex.size() == num_tstrips * tstrip_length, NULL);
 
-  GeomTristrip *geom = new GeomTristrip;
-  geom->set_num_prims(num_tstrips);
-  geom->set_lengths(lengths);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    geom_node->add_geom(geom);
+
+  } else {
+    PTA_Vertexf coords;
+    PTA_Normalf norms;
+    coords.reserve(num_verts);
+    
+    for (int yi = 0; yi < num_y_verts; yi++) {
+      for (int xi = 0; xi < num_x_verts; xi++) {
+        LPoint2f film = LPoint2f((float)xi * x_scale - 1.0f,
+                                 (float)yi * y_scale - 1.0f);
+        
+        // Reduce the image by the fill ratio.
+        film *= fill_ratio;
+        
+        LPoint3f near_point, far_point;
+        lens->extrude(film, near_point, far_point);
+        LPoint3f point = near_point + t * (far_point - near_point);
+        
+        // Normals aren't often needed on projection screens, but you
+        // never know.
+        LVector3f normal;
+        lens->extrude_vec(film, normal);
+        
+        coords.push_back(point * rel_mat);
+        norms.push_back(-normalize(normal * rel_mat));
+      }
+    }
+    nassertr((int)coords.size() == num_verts, NULL);
+
+    // Now synthesize a triangle mesh.  We run triangle strips
+    // horizontally across the grid.
+    int num_tstrips = (num_y_verts-1);
+    int tstrip_length = 2*(num_x_verts-1)+2;
+    
+    PTA_int lengths;
+    PTA_ushort vindex;
+    
+    // Set the lengths array.  we are creating num_tstrips t-strips,
+    // each of which has tstrip_length vertices.
+    lengths.reserve(num_tstrips);
+    int n;
+    for (n = 0; n < num_tstrips; n++) {
+      lengths.push_back(tstrip_length);
+    }
+    nassertr((int)lengths.size() == num_tstrips, NULL);
+    
+    // Now fill up the index array into the vertices.  This lays out the
+    // order of the vertices in each t-strip.
+    vindex.reserve(num_tstrips * tstrip_length);
+    n = 0;
+    int ti, si;
+    for (ti = 1; ti < num_y_verts; ti++) {
+      vindex.push_back(ti * num_x_verts);
+      for (si = 1; si < num_x_verts; si++) {
+        vindex.push_back((ti - 1) * num_x_verts + (si-1));
+        vindex.push_back(ti * num_x_verts + si);
+      }
+      vindex.push_back((ti - 1) * num_x_verts + (num_x_verts-1));
+    }
+    nassertr((int)vindex.size() == num_tstrips * tstrip_length, NULL);
 
-  geom->set_coords(coords, G_PER_VERTEX, vindex);
-  geom->set_normals(norms, G_PER_VERTEX, vindex);
+    GeomTristrip *geom = new GeomTristrip;
+    geom->set_num_prims(num_tstrips);
+    geom->set_lengths(lengths);
 
-  // Make it white.
-  PTA_Colorf colors;
-  colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-  geom->set_colors(colors, G_OVERALL);
+    geom->set_coords(coords, G_PER_VERTEX, vindex);
+    geom->set_normals(norms, G_PER_VERTEX, vindex);
 
-  // Now create a GeomNode to hold this mesh.
-  PT(GeomNode) geom_node = new GeomNode(screen_name);
-  geom_node->add_geom(geom);
+    // Make it white.
+    PTA_Colorf colors;
+    colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+    geom->set_colors(colors, G_OVERALL);
+
+    geom_node->add_geom(geom);
+  }
 
   _stale = true;
   ++_last_screen;
@@ -535,55 +596,106 @@ recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
      0.0f,-0.5f, 0.0f,
      0.5f, 0.5f, 1.0f);
 
-  PTA_TexCoordf uvs;
-  PTA_ushort color_index;
   Lens *lens = _projector_node->get_lens();
   nassertv(lens != (Lens *)NULL);
 
   const LMatrix3f &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
 
-  // Iterate through all the vertices in the Geom.
-  int num_vertices = geom->get_num_vertices();
-  Geom::VertexIterator vi = geom->make_vertex_iterator();
-
-  for (int i = 0; i < num_vertices; i++) {
-    const Vertexf &vert = geom->get_next_vertex(vi);
-
-    // For each vertex, project to the film plane.
-    LPoint2f film(0.0, 0.0);
-    bool good = lens->project(vert * rel_mat, film);
+  if (geom->is_of_type(qpGeom::get_class_type())) {
+    qpGeom *qpgeom = DCAST(qpGeom, geom);
+    // Iterate through all the vertices in the Geom.
+
+    CPT(qpGeomVertexData) vdata = qpgeom->get_vertex_data();
+    if (!vdata->has_column(_texcoord_name)) {
+      // We need to add a new column for the new texcoords.
+      vdata = vdata->replace_column
+        (_texcoord_name, 2, qpGeomVertexColumn::NT_float32,
+         qpGeomVertexColumn::C_texcoord, qpGeomUsageHint::UH_dynamic, true);
+      qpgeom->set_vertex_data(vdata);
+    }
+    if (_vignette_on && !vdata->has_column(InternalName::get_color())) {
+      // We need to add a column for color.
+      vdata = vdata->replace_column
+        (InternalName::get_color(), 1, qpGeomVertexColumn::NT_packed_dabc,
+         qpGeomVertexColumn::C_color, qpGeomUsageHint::UH_dynamic, true);
+      qpgeom->set_vertex_data(vdata);
+    }
 
-    // Now the lens gives us coordinates in the range [-1, 1].
-    // Rescale these to [0, 1].
-    uvs.push_back(film * to_uv);
+    qpGeomVertexWriter texcoord(qpgeom->modify_vertex_data(), _texcoord_name);
+    qpGeomVertexWriter color(qpgeom->modify_vertex_data());
+    qpGeomVertexReader vertex(qpgeom->get_vertex_data(), InternalName::get_vertex());
 
-    // If we have vignette color in effect, color the vertex according
-    // to whether it fell in front of the lens or not.
     if (_vignette_on) {
-      color_index.push_back(good ? 1 : 0);
+      color.set_column(InternalName::get_color());
     }
-  }
 
-  // Now set the UV's.  If the geom already has indexed UV's, we need
-  // to make a new index for the geom.
-  geom->remove_texcoords(_texcoord_name);
-  if (!geom->are_texcoords_indexed()) {
-    // Simple case: no indexing needed.
-    geom->set_texcoords(_texcoord_name, uvs);
+    while (!vertex.is_at_end()) {
+      Vertexf vert = vertex.get_data3f();
+      
+      // For each vertex, project to the film plane.
+      LPoint2f film(0.0, 0.0);
+      bool good = lens->project(vert * rel_mat, film);
+      
+      // Now the lens gives us coordinates in the range [-1, 1].
+      // Rescale these to [0, 1].
+      texcoord.set_data2f(film * to_uv);
+
+      // If we have vignette color in effect, color the vertex according
+      // to whether it fell in front of the lens or not.
+      if (_vignette_on) {
+        if (good) {
+          color.set_data4f(_frame_color);
+        } else {
+          color.set_data4f(_vignette_color);
+        }
+      }
+    }
 
   } else {
-    // Harder case: we need to make up an index.  But this isn't
-    // terribly hard.
-    PTA_ushort index = PTA_ushort::empty_array(num_vertices);
+    // Iterate through all the vertices in the Geom.
+    PTA_TexCoordf uvs;
+    PTA_ushort color_index;
+    int num_vertices = geom->get_num_vertices();
+    Geom::VertexIterator vi = geom->make_vertex_iterator();
+
     for (int i = 0; i < num_vertices; i++) {
-      index[i] = i;
+      const Vertexf &vert = geom->get_next_vertex(vi);
+      
+      // For each vertex, project to the film plane.
+      LPoint2f film(0.0, 0.0);
+      bool good = lens->project(vert * rel_mat, film);
+      
+      // Now the lens gives us coordinates in the range [-1, 1].
+      // Rescale these to [0, 1].
+      uvs.push_back(film * to_uv);
+      
+      // If we have vignette color in effect, color the vertex according
+      // to whether it fell in front of the lens or not.
+      if (_vignette_on) {
+        color_index.push_back(good ? 1 : 0);
+      }
     }
-    geom->set_texcoords(_texcoord_name, uvs, index);
-  }
 
+    // Now set the UV's.  If the geom already has indexed UV's, we need
+    // to make a new index for the geom.
+    geom->remove_texcoords(_texcoord_name);
+    if (!geom->are_texcoords_indexed()) {
+      // Simple case: no indexing needed.
+      geom->set_texcoords(_texcoord_name, uvs);
+      
+    } else {
+      // Harder case: we need to make up an index.  But this isn't
+      // terribly hard.
+      PTA_ushort index = PTA_ushort::empty_array(num_vertices);
+      for (int i = 0; i < num_vertices; i++) {
+        index[i] = i;
+      }
+      geom->set_texcoords(_texcoord_name, uvs, index);
+    }
 
-  if (_vignette_on) {
-    geom->set_colors(_colors, G_PER_VERTEX, color_index);
+    if (_vignette_on) {
+      geom->set_colors(_colors, G_PER_VERTEX, color_index);
+    }
   }
 }
 
@@ -702,29 +814,49 @@ make_mesh_geom_node(const WorkingNodePath &np, const NodePath &camera,
 ////////////////////////////////////////////////////////////////////
 PT(Geom) ProjectionScreen::
 make_mesh_geom(const Geom *geom, Lens *lens, LMatrix4f &rel_mat) {
-  Geom *new_geom = geom->make_copy();
-  PT(Geom) result = new_geom;
-
-  PTA_Vertexf coords;
-  GeomBindType bind;
-  PTA_ushort vindex;
-
-  new_geom->get_coords(coords, bind, vindex);
-
-  PTA_Vertexf new_coords;
-  new_coords.reserve(coords.size());
-  for (int i = 0; i < (int)coords.size(); i++) {
-    const Vertexf &vert = coords[i];
+  if (geom->is_of_type(qpGeom::get_class_type())) {
+    PT(qpGeom) new_geom = new qpGeom(*DCAST(qpGeom, geom));
+
+    qpGeomVertexRewriter vertex(new_geom->modify_vertex_data(), 
+                                InternalName::get_vertex());
+    while (!vertex.is_at_end()) {
+      Vertexf vert = vertex.get_data3f();
+      
+      // Project each vertex into the film plane, but use three
+      // dimensions so the Z coordinate remains meaningful.
+      LPoint3f film(0.0f, 0.0f, 0.0f);
+      lens->project(vert * rel_mat, film);
+      
+      vertex.set_data3f(film);
+    }      
+
+    return new_geom.p();
+    
+  } else {
+    Geom *new_geom = geom->make_copy();
+    PT(Geom) result = new_geom;
 
-    // Project each vertex into the film plane, but use three
-    // dimensions so the Z coordinate remains meaningful.
-    LPoint3f film(0.0f, 0.0f, 0.0f);
-    lens->project(vert * rel_mat, film);
+    PTA_Vertexf coords;
+    GeomBindType bind;
+    PTA_ushort vindex;
+    
+    new_geom->get_coords(coords, bind, vindex);
+    
+    PTA_Vertexf new_coords;
+    new_coords.reserve(coords.size());
+    for (int i = 0; i < (int)coords.size(); i++) {
+      const Vertexf &vert = coords[i];
+      
+      // Project each vertex into the film plane, but use three
+      // dimensions so the Z coordinate remains meaningful.
+      LPoint3f film(0.0f, 0.0f, 0.0f);
+      lens->project(vert * rel_mat, film);
+      
+      new_coords.push_back(film);
+    }
+    
+    new_geom->set_coords(new_coords, bind, vindex);
 
-    new_coords.push_back(film);
+    return result;
   }
-
-  new_geom->set_coords(new_coords, bind, vindex);
-
-  return result;
 }

+ 22 - 0
panda/src/egg/eggVertexPool.cxx

@@ -250,6 +250,28 @@ has_colors() const {
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggVertexPool::has_nonwhite_colors
+//       Access: Public
+//  Description: Returns true if any vertex in the pool has a color
+//               defined other than white, false if no vertices have
+//               colors, or if all colors are white.
+////////////////////////////////////////////////////////////////////
+bool EggVertexPool::
+has_nonwhite_colors() const {
+  IndexVertices::const_iterator ivi;
+  for (ivi = _index_vertices.begin(); ivi != _index_vertices.end(); ++ivi) {
+    EggVertex *vertex = (*ivi).second;
+    if (vertex->has_color() && 
+        (vertex->get_color() != Colorf(1.0, 1.0, 1.0, 1.0) ||
+         !vertex->_drgbas.empty())) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: EggVertexPool::has_uvs
 //       Access: Public

+ 1 - 0
panda/src/egg/eggVertexPool.h

@@ -96,6 +96,7 @@ PUBLISHED:
   int get_num_dimensions() const;
   bool has_normals() const;
   bool has_colors() const;
+  bool has_nonwhite_colors() const;
   bool has_uvs() const;
   void get_uv_names(vector_string &uv_names) const;
 

+ 14 - 1
panda/src/egg2pg/eggBinner.cxx

@@ -19,6 +19,8 @@
 #include "eggBinner.h"
 #include "eggRenderState.h"
 #include "eggPrimitive.h"
+#include "eggNurbsSurface.h"
+#include "eggNurbsCurve.h"
 #include "eggSwitchCondition.h"
 #include "eggGroup.h"
 #include "dcast.h"
@@ -58,7 +60,13 @@ prepare_node(EggNode *node) {
 ////////////////////////////////////////////////////////////////////
 int EggBinner::
 get_bin_number(const EggNode *node) {
-  if (node->is_of_type(EggPrimitive::get_class_type())) {
+  if (node->is_of_type(EggNurbsSurface::get_class_type())) {
+    return (int)BN_nurbs_surface;
+
+  } else if (node->is_of_type(EggNurbsCurve::get_class_type())) {
+    return (int)BN_nurbs_curve;
+
+  } else if (node->is_of_type(EggPrimitive::get_class_type())) {
     return (int)BN_polyset;
 
   } else if (node->is_of_type(EggGroup::get_class_type())) {
@@ -115,6 +123,11 @@ sorts_less(int bin_number, const EggNode *a, const EggNode *b) {
       // Group LOD nodes in order by switching center.
       return (swda._center.compare_to(swdb._center) < 0);
     }
+
+  case BN_nurbs_surface:
+  case BN_nurbs_curve:
+    // Nurbs curves and surfaces are always binned individually.
+    return a < b;
       
   case BN_none:
     break;

+ 2 - 0
panda/src/egg2pg/eggBinner.h

@@ -43,6 +43,8 @@ public:
     BN_none = 0,
     BN_polyset,
     BN_lod,
+    BN_nurbs_surface,
+    BN_nurbs_curve,
   };
 
   EggBinner(EggLoader &loader);

+ 29 - 11
panda/src/egg2pg/eggLoader.cxx

@@ -420,7 +420,7 @@ make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
 
     int nindex =
       comp_verts_maker.add_normal(egg_prim->get_normal(),
-                                   egg_prim->_dnormals, mat);
+                                  egg_prim->_dnormals, mat);
 
     bprim.set_normal(nindex);
   }
@@ -428,7 +428,7 @@ make_indexed_primitive(EggPrimitive *egg_prim, PandaNode *parent,
   if (egg_prim->has_color() && !egg_false_color) {
     int cindex =
       comp_verts_maker.add_color(egg_prim->get_color(),
-                                  egg_prim->_drgbas);
+                                 egg_prim->_drgbas);
     bprim.set_color(cindex);
   }
 
@@ -1541,6 +1541,28 @@ make_node(EggBin *egg_bin, PandaNode *parent) {
   case EggBinner::BN_lod:
     return make_lod(egg_bin, parent);
 
+  case EggBinner::BN_nurbs_surface:
+    {
+      nassertr(!egg_bin->empty(), NULL);
+      EggNode *child = egg_bin->get_first_child();
+      EggNurbsSurface *egg_nurbs;
+      DCAST_INTO_R(egg_nurbs, child, NULL);
+      const LMatrix4d &mat = egg_nurbs->get_vertex_to_node();
+      make_nurbs_surface(egg_nurbs, parent, mat);
+    }
+    return NULL;
+
+  case EggBinner::BN_nurbs_curve:
+    {
+      nassertr(!egg_bin->empty(), NULL);
+      EggNode *child = egg_bin->get_first_child();
+      EggNurbsCurve *egg_nurbs;
+      DCAST_INTO_R(egg_nurbs, child, NULL);
+      const LMatrix4d &mat = egg_nurbs->get_vertex_to_node();
+      make_nurbs_curve(egg_nurbs, parent, mat);
+    }
+    return NULL;
+
   case EggBinner::BN_none:
     break;
   }
@@ -1929,7 +1951,8 @@ make_vertex_data(const EggRenderState *render_state,
        qpGeomVertexColumn::NT_float32, qpGeomVertexColumn::C_vector);
   }
 
-  if (vertex_pool->has_colors()) {
+  bool has_colors = vertex_pool->has_nonwhite_colors();
+  if (has_colors) {
     array_format->add_column
       (InternalName::get_color(), 1, 
        qpGeomVertexColumn::NT_packed_dabc, qpGeomVertexColumn::C_color);
@@ -1994,7 +2017,7 @@ make_vertex_data(const EggRenderState *render_state,
                        InternalName::get_normal(), 3);
         }
       }
-      if (vertex->has_color()) {
+      if (has_colors && vertex->has_color()) {
         EggMorphColorList::const_iterator mci;
         for (mci = vertex->_drgbas.begin(); mci != vertex->_drgbas.end(); ++mci) {
           slider_names.insert((*mci).get_name());
@@ -2090,7 +2113,7 @@ make_vertex_data(const EggRenderState *render_state,
       }
     }
 
-    if (vertex->has_color()) {
+    if (has_colors && vertex->has_color()) {
       gvw.set_column(InternalName::get_color());
       gvw.add_data4f(vertex->get_color());
 
@@ -2372,13 +2395,8 @@ make_sphere(EggGroup *egg_group, EggGroup::CollideFlags flags,
       //egg2pg_cat.debug() << "make_sphere radius: " << radius << "\n";
       vi = vertices.begin();
       EggVertex *clr_vtx = (*vi);
-      if (clr_vtx->has_color()) {
-        color = clr_vtx->get_color();
-      } else {
-        color = Colorf(1.0,1.0,1.0,1.0);
-      }
+      color = clr_vtx->get_color();
       success = true;
-
     }
   }
   return success;

+ 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_v3cpt2(),
+      (string(), qpGeomVertexFormat::get_v3t2(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());

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

@@ -2324,6 +2324,10 @@ begin_draw_primitives(const qpGeom *geom, const qpGeomMunger *munger,
     GLP(EnableClientState)(GL_COLOR_ARRAY);
   } else {
     GLP(DisableClientState)(GL_COLOR_ARRAY);
+
+    // Since we don't have per-vertex color, the implicit color is
+    // white.
+    GLP(Color4f)(1.0f, 1.0f, 1.0f, 1.0f);
   }
 
   // Now set up each of the active texture coordinate stages--or at

+ 11 - 0
panda/src/gobj/geom.cxx

@@ -329,6 +329,17 @@ transform_vertices(const LMatrix4f &mat) {
   set_coords(new_coords, index);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Geom::check_valid
+//       Access: Published
+//  Description: This is only here temporarily; it has meaning at the
+//               qpGeom level.
+////////////////////////////////////////////////////////////////////
+bool Geom::
+check_valid() const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Geom::set_coords
 //       Access: Published

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

@@ -136,6 +136,7 @@ public:
 
 PUBLISHED:
   virtual void transform_vertices(const LMatrix4f &mat);
+  virtual bool check_valid() const;
 
   void set_coords(const PTA_Vertexf &coords,
                   const PTA_ushort &vindex = PTA_ushort());

+ 209 - 55
panda/src/gobj/lens.cxx

@@ -21,6 +21,9 @@
 #include "compose_matrix.h"
 #include "look_at.h"
 #include "geomLinestrip.h"
+#include "qpgeom.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomVertexWriter.h"
 #include "boundingHexahedron.h"
 #include "indent.h"
 #include "config_gobj.h"
@@ -67,8 +70,7 @@ operator = (const Lens &copy) {
   _user_flags = copy._user_flags;
   _comp_flags = 0;
 
-  // We don't copy the _geom_coords array.  That's unique to each
-  // Lens.
+  // We don't copy the _geom_data.  That's unique to each Lens.
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -873,74 +875,137 @@ PT(Geom) Lens::
 make_geometry() {
   // The default behavior for make_geometry() will be to draw a
   // hexahedron around the eight vertices of the frustum.  If the lens
-  // is non-linear, the hexahedron will be curved; in this case, we'll
+  // is non-linear, the hexahedron will be curved; in that case, we'll
   // subdivide the lines into several segments to get an approximation
   // of the curve.
 
-  // First, define all the points we'll use in this Geom.  That's one
-  // point at each corner of the near and far planes (and possibly
-  // more points along the edges).
-  int num_segments = define_geom_coords();
-  if (num_segments == 0) {
-    // Can't do a frustum.
-    _geom_coords.clear();
-    return (Geom *)NULL;
-  }
+  if (use_qpgeom) {
+    // First, define all the points we'll use in this Geom.  That's one
+    // point at each corner of the near and far planes (and possibly
+    // more points along the edges).
+    int num_segments = define_geom_data();
+    if (num_segments == 0) {
+      // Can't do a frustum.
+      _geom_data.clear();
+      return (Geom *)NULL;
+    }
 
-  // Now string together the line segments.
-  PTA_ushort vindex;
-  PTA_int lengths;
-  PTA_Colorf colors;
+    // Now string together the line segments.
+    PT(qpGeomLinestrips) line = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
 
-  int num_points = num_segments * 4;
+    // Draw a frame around the near plane.
+    int i, si;
+    for (i = 0; i < 4; ++i) {
+      for (si = 0; si < num_segments; ++si) {
+        line->add_vertex(i * 2 + si * (4 * 2) + 0);
+      }
+    }
+    line->add_vertex(0);
+    line->close_primitive();
 
-  // Draw a frame around the near plane.
-  int i;
-  for (i = 0; i < num_points; i++) {
-    vindex.push_back(i * num_segments * 2);
-  }
-  vindex.push_back(0);
-  lengths.push_back(num_points + 1);
+    // Draw a frame around the far plane.
+    for (i = 0; i < 4; ++i) {
+      for (si = 0; si < num_segments; ++si) {
+        line->add_vertex(i * 2 + si * (4 * 2) + 1);
+      }
+    }
+    line->add_vertex(1);
+    line->close_primitive();
 
-  // Draw a frame around the far plane.
-  for (i = 0; i < num_points; i++) {
-    vindex.push_back(i * num_segments * 2 + 1);
-  }
-  vindex.push_back(1);
-  lengths.push_back(num_points + 1);
+    // Draw connecting lines at the corners.
+    line->add_vertex(0 * 2 + 0);
+    line->add_vertex(0 * 2 + 1);
+    line->close_primitive();
+
+    line->add_vertex(1 * 2 + 0);
+    line->add_vertex(1 * 2 + 1);
+    line->close_primitive();
+
+    line->add_vertex(2 * 2 + 0);
+    line->add_vertex(2 * 2 + 1);
+    line->close_primitive();
+
+    line->add_vertex(3 * 2 + 0);
+    line->add_vertex(3 * 2 + 1);
+    line->close_primitive();
 
-  // Draw connecting lines at the corners.
-  vindex.push_back(0);
-  vindex.push_back(1);
-  lengths.push_back(2);
+    // And one more line for the viewing axis.
+    line->add_vertex(num_segments * (4 * 2) + 0);
+    line->add_vertex(num_segments * (4 * 2) + 1);
+    line->close_primitive();
 
-  vindex.push_back(num_segments * 2 + 0);
-  vindex.push_back(num_segments * 2+ 1);
-  lengths.push_back(2);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(_geom_data);
+    geom->add_primitive(line);
 
-  vindex.push_back(num_segments * 4 + 0);
-  vindex.push_back(num_segments * 4 + 1);
-  lengths.push_back(2);
+    return geom.p();
+
+  } else {
+    // First, define all the points we'll use in this Geom.  That's one
+    // point at each corner of the near and far planes (and possibly
+    // more points along the edges).
+    int num_segments = define_geom_coords();
+    if (num_segments == 0) {
+      // Can't do a frustum.
+      _geom_coords.clear();
+      return (Geom *)NULL;
+    }
+
+    // Now string together the line segments.
+    PTA_ushort vindex;
+    PTA_int lengths;
+    PTA_Colorf colors;
+
+    int num_points = num_segments * 4;
+
+    // Draw a frame around the near plane.
+    int i;
+    for (i = 0; i < num_points; i++) {
+      vindex.push_back(i * num_segments * 2);
+    }
+    vindex.push_back(0);
+    lengths.push_back(num_points + 1);
+
+    // Draw a frame around the far plane.
+    for (i = 0; i < num_points; i++) {
+      vindex.push_back(i * num_segments * 2 + 1);
+    }
+    vindex.push_back(1);
+    lengths.push_back(num_points + 1);
 
-  vindex.push_back(num_segments * 6 + 0);
-  vindex.push_back(num_segments * 6 + 1);
-  lengths.push_back(2);
+    // Draw connecting lines at the corners.
+    vindex.push_back(0);
+    vindex.push_back(1);
+    lengths.push_back(2);
 
-  // And one more line for the viewing axis.
-  vindex.push_back(num_segments * 8 + 0);
-  vindex.push_back(num_segments * 8 + 1);
-  lengths.push_back(2);
+    vindex.push_back(num_segments * 2 + 0);
+    vindex.push_back(num_segments * 2+ 1);
+    lengths.push_back(2);
 
-  // We just specify overall color.
-  colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+    vindex.push_back(num_segments * 4 + 0);
+    vindex.push_back(num_segments * 4 + 1);
+    lengths.push_back(2);
 
-  GeomLinestrip *gline = new GeomLinestrip;
-  gline->set_coords(_geom_coords, vindex);
-  gline->set_colors(colors, G_OVERALL);
-  gline->set_lengths(lengths);
-  gline->set_num_prims(lengths.size());
+    vindex.push_back(num_segments * 6 + 0);
+    vindex.push_back(num_segments * 6 + 1);
+    lengths.push_back(2);
 
-  return gline;
+    // And one more line for the viewing axis.
+    vindex.push_back(num_segments * 8 + 0);
+    vindex.push_back(num_segments * 8 + 1);
+    lengths.push_back(2);
+
+    // We just specify overall color.
+    colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+
+    GeomLinestrip *gline = new GeomLinestrip;
+    gline->set_coords(_geom_coords, vindex);
+    gline->set_colors(colors, G_OVERALL);
+    gline->set_lengths(lengths);
+    gline->set_num_prims(lengths.size());
+
+    return gline;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1070,6 +1135,18 @@ throw_change_event() {
       define_geom_coords();
     }
   }
+  if (!_geom_data.is_null()) {
+    if (_geom_data->get_ref_count() == 1) {
+      // No one's using the data any more (there are no references to
+      // it other than this one), so don't bother to recompute it;
+      // just release it.
+      _geom_data.clear();
+    } else {
+      // Someone still has a handle to the data, so recompute it for
+      // them.
+      define_geom_data();
+    }
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -1659,6 +1736,83 @@ define_geom_coords() {
   return num_segments;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: Lens::define_geom_data
+//       Access: Private
+//  Description: Adjusts (or defines for the first time) all the
+//               vertices in the _geom_data to match the properties of
+//               the lens.  This will update the visual representation
+//               of the lens's frustum to match the changing
+//               parameters.  Returns the number of line segments per
+//               edge.
+////////////////////////////////////////////////////////////////////
+int Lens::
+define_geom_data() {
+  int num_segments = 1;
+  if (!is_linear()) {
+    num_segments = 10;
+  }
+  
+  if (_geom_data == (qpGeomVertexData *)NULL) {
+    _geom_data = new qpGeomVertexData
+      ("lens", qpGeomVertexFormat::get_v3(),
+       qpGeomUsageHint::UH_dynamic);
+  }
+
+  qpGeomVertexWriter vertex(_geom_data, InternalName::get_vertex());
+  LPoint3f near_point, far_point;
+  for (int si = 0; si < num_segments; si++) {
+    float t = 2.0f * (float)si / (float)num_segments;
+
+    // Upper left, top edge.
+    LPoint2f p1(-1.0f + t, 1.0f);
+    if (!extrude(p1, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    vertex.add_data3f(near_point);
+    vertex.add_data3f(far_point);
+
+    // Upper right, right edge.
+    LPoint2f p2(1.0f, 1.0f - t);
+    if (!extrude(p2, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    vertex.add_data3f(near_point);
+    vertex.add_data3f(far_point);
+
+    // Lower right, bottom edge.
+    LPoint2f p3(1.0f - t, -1.0f);
+    if (!extrude(p3, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    vertex.add_data3f(near_point);
+    vertex.add_data3f(far_point);
+
+    // Lower left, left edge.
+    LPoint2f p4(-1.0f, -1.0f + t);
+    if (!extrude(p4, near_point, far_point)) {
+      // Hey, this point is off the lens!  Can't do a frustum.
+      return 0;
+    }
+    vertex.add_data3f(near_point);
+    vertex.add_data3f(far_point);
+  }
+
+  // Finally, add one more pair for the viewing axis.
+  LPoint3f near_axis = LPoint3f::origin(_cs) + LVector3f::forward(_cs) * _near_distance;
+  LPoint3f far_axis = LPoint3f::origin(_cs) + LVector3f::forward(_cs) * _far_distance;
+  const LMatrix4f &lens_mat = get_lens_mat();
+  near_axis = near_axis * lens_mat;
+  far_axis = far_axis * lens_mat;
+  vertex.add_data3f(near_axis);
+  vertex.add_data3f(far_axis);
+
+  return num_segments;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: Lens::build_shear_mat
 //       Access: Private, Static

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

@@ -25,6 +25,8 @@
 #include "luse.h"
 #include "geom.h"
 #include "updateSeq.h"
+#include "qpgeomVertexData.h"
+#include "pointerTo.h"
 
 class BoundingVolume;
 
@@ -182,6 +184,7 @@ protected:
 private:
   static void resequence_fov_triad(char &newest, char &older_a, char &older_b);
   int define_geom_coords();
+  int define_geom_data();
   static void build_shear_mat(LMatrix4f &shear_mat,
                               const LPoint3f &cul, const LPoint3f &cur,
                               const LPoint3f &cll, const LPoint3f &clr);
@@ -252,6 +255,7 @@ protected:
   char _focal_length_seq, _fov_seq, _film_size_seq;
 
   PTA_Vertexf _geom_coords;
+  PT(qpGeomVertexData) _geom_data;
 
 public:
   virtual void write_datagram(BamWriter *manager, Datagram &dg);

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

@@ -107,40 +107,6 @@ modify_primitive(int i) {
   return cdata->_primitives[i];
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: qpGeom::set_primitive
-//       Access: Published
-//  Description: Replaces the ith GeomPrimitive object stored within
-//               the Geom with the new object.
-////////////////////////////////////////////////////////////////////
-INLINE void qpGeom::
-set_primitive(int i, const qpGeomPrimitive *primitive) {
-  clear_cache();
-  CDWriter cdata(_cycler);
-  nassertv(i >= 0 && i < (int)cdata->_primitives.size());
-
-  // All primitives within a particular Geom must have the same
-  // primitive type.
-  nassertv(cdata->_primitive_type == qpGeomPrimitive::PT_none ||
-           cdata->_primitive_type == primitive->get_primitive_type());
-  if (cdata->_got_usage_hint &&
-      cdata->_primitives[i]->get_usage_hint() != primitive->get_usage_hint()) {
-    if (cdata->_primitives[i]->get_usage_hint() < primitive->get_usage_hint()) {
-      // If we're reducing the usage hint, we might also be reducing
-      // the minimum usage hit.
-      cdata->_usage_hint = min(cdata->_usage_hint, primitive->get_usage_hint());
-    } else { // (cdata->_primitives[i]->get_usage_hint() > primitive->get_usage_hint())
-      // If we're increasing it, we might have to rederive the minimum.
-      if (cdata->_usage_hint == cdata->_primitives[i]->get_usage_hint()) {
-        cdata->_got_usage_hint = false;
-      }
-    }
-  }
-  cdata->_primitives[i] = (qpGeomPrimitive *)primitive;
-  cdata->_primitive_type = primitive->get_primitive_type();
-  cdata->_modified = qpGeom::get_next_modified();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::get_modified
 //       Access: Published

+ 91 - 1
panda/src/gobj/qpgeom.cxx

@@ -133,12 +133,49 @@ modify_vertex_data() {
 ////////////////////////////////////////////////////////////////////
 void qpGeom::
 set_vertex_data(const qpGeomVertexData *data) {
+  nassertv(check_will_be_valid(data));
   clear_cache();
   CDWriter cdata(_cycler);
   cdata->_data = (qpGeomVertexData *)data;
   mark_bound_stale();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::set_primitive
+//       Access: Published
+//  Description: Replaces the ith GeomPrimitive object stored within
+//               the Geom with the new object.
+////////////////////////////////////////////////////////////////////
+void qpGeom::
+set_primitive(int i, const qpGeomPrimitive *primitive) {
+  clear_cache();
+  CDWriter cdata(_cycler);
+  nassertv(i >= 0 && i < (int)cdata->_primitives.size());
+  nassertv(primitive->check_valid(cdata->_data));
+
+  // All primitives within a particular Geom must have the same
+  // fundamental primitive type (triangles, points, or lines).
+  nassertv(cdata->_primitive_type == qpGeomPrimitive::PT_none ||
+           cdata->_primitive_type == primitive->get_primitive_type());
+
+  if (cdata->_got_usage_hint &&
+      cdata->_primitives[i]->get_usage_hint() != primitive->get_usage_hint()) {
+    if (cdata->_primitives[i]->get_usage_hint() < primitive->get_usage_hint()) {
+      // If we're reducing the usage hint, we might also be reducing
+      // the minimum usage hit.
+      cdata->_usage_hint = min(cdata->_usage_hint, primitive->get_usage_hint());
+    } else { // (cdata->_primitives[i]->get_usage_hint() > primitive->get_usage_hint())
+      // If we're increasing it, we might have to rederive the minimum.
+      if (cdata->_usage_hint == cdata->_primitives[i]->get_usage_hint()) {
+        cdata->_got_usage_hint = false;
+      }
+    }
+  }
+  cdata->_primitives[i] = (qpGeomPrimitive *)primitive;
+  cdata->_primitive_type = primitive->get_primitive_type();
+  cdata->_modified = qpGeom::get_next_modified();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::add_primitive
 //       Access: Published
@@ -151,8 +188,11 @@ void qpGeom::
 add_primitive(const qpGeomPrimitive *primitive) {
   clear_cache();
   CDWriter cdata(_cycler);
+
+  nassertv(primitive->check_valid(cdata->_data));
+
   // All primitives within a particular Geom must have the same
-  // primitive type.
+  // fundamental primitive type (triangles, points, or lines).
   nassertv(cdata->_primitive_type == qpGeomPrimitive::PT_none ||
            cdata->_primitive_type == primitive->get_primitive_type());
 
@@ -340,6 +380,30 @@ munge_geom(const qpGeomMunger *munger,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::check_valid
+//       Access: Published
+//  Description: Verifies that the all of the primitives within the
+//               geom reference vertices that actually exist within
+//               the geom's GeomVertexData.  Returns true if the geom
+//               appears to be valid, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool qpGeom::
+check_valid() const {
+  CDReader cdata(_cycler);
+
+  Primitives::const_iterator pi;
+  for (pi = cdata->_primitives.begin(); 
+       pi != cdata->_primitives.end();
+       ++pi) {
+    if (!(*pi)->check_valid(cdata->_data)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::output
 //       Access: Published
@@ -523,6 +587,32 @@ recompute_bound() {
   return bound;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeom::check_will_be_valid
+//       Access: Private
+//  Description: Verifies that the all of the primitives within the
+//               geom reference vertices that actually exist within
+//               the indicated GeomVertexData (presumably in
+//               preparation for assigning the geom to use this data).
+//               Returns true if the data appears to be valid, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+bool qpGeom::
+check_will_be_valid(const qpGeomVertexData *vertex_data) const {
+  CDReader cdata(_cycler);
+
+  Primitives::const_iterator pi;
+  for (pi = cdata->_primitives.begin(); 
+       pi != cdata->_primitives.end();
+       ++pi) {
+    if (!(*pi)->check_valid(vertex_data)) {
+      return false;
+    }
+  }
+
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeom::reset_usage_hint
 //       Access: Private

+ 8 - 1
panda/src/gobj/qpgeom.h

@@ -76,7 +76,7 @@ PUBLISHED:
   INLINE int get_num_primitives() const;
   INLINE const qpGeomPrimitive *get_primitive(int i) const;
   INLINE qpGeomPrimitive *modify_primitive(int i);
-  INLINE void set_primitive(int i, const qpGeomPrimitive *primitive);
+  void set_primitive(int i, const qpGeomPrimitive *primitive);
   void add_primitive(const qpGeomPrimitive *primitive);
   void remove_primitive(int i);
   void clear_primitives();
@@ -84,11 +84,15 @@ PUBLISHED:
   int get_num_bytes() const;
   INLINE UpdateSeq get_modified() const;
 
+  // Temporarily virtual.
   virtual void transform_vertices(const LMatrix4f &mat);
 
   void munge_geom(const qpGeomMunger *munger,
                   CPT(qpGeom) &result, CPT(qpGeomVertexData) &data) const;
 
+  // Temporarily virtual.
+  virtual bool check_valid() const;
+
   void output(ostream &out) const;
   void write(ostream &out, int indent_level = 0) const;
 
@@ -109,6 +113,9 @@ public:
 protected:
   virtual BoundingVolume *recompute_bound();
 
+private:
+  bool check_will_be_valid(const qpGeomVertexData *vertex_data) const;
+
 private:
   typedef pvector<PT(qpGeomPrimitive) > Primitives;
 

+ 11 - 0
panda/src/gobj/qpgeomLines.cxx

@@ -94,6 +94,17 @@ get_num_vertices_per_primitive() const {
   return 2;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLines::get_min_num_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: Returns the minimum number of vertices that must be
+//               added before close_primitive() may legally be called.
+////////////////////////////////////////////////////////////////////
+int qpGeomLines::
+get_min_num_vertices_per_primitive() const {
+  return 2;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomLines::draw
 //       Access: Public, Virtual

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

@@ -39,6 +39,7 @@ public:
   virtual PrimitiveType get_primitive_type() const;
 
   virtual int get_num_vertices_per_primitive() const;
+  virtual int get_min_num_vertices_per_primitive() const;
 
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;

+ 11 - 0
panda/src/gobj/qpgeomLinestrips.cxx

@@ -79,6 +79,17 @@ get_primitive_type() const {
   return PT_lines;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomLinestrips::get_min_num_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: Returns the minimum number of vertices that must be
+//               added before close_primitive() may legally be called.
+////////////////////////////////////////////////////////////////////
+int qpGeomLinestrips::
+get_min_num_vertices_per_primitive() const {
+  return 2;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomLinestrips::draw
 //       Access: Public, Virtual

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

@@ -38,6 +38,8 @@ public:
   virtual PT(qpGeomPrimitive) make_copy() const;
   virtual PrimitiveType get_primitive_type() const;
 
+  virtual int get_min_num_vertices_per_primitive() const;
+
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;
 

+ 11 - 0
panda/src/gobj/qpgeomPoints.cxx

@@ -94,6 +94,17 @@ get_num_vertices_per_primitive() const {
   return 1;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPoints::get_min_num_vertices_per_primitive
+//       Access: Public, Virtual
+//  Description: Returns the minimum number of vertices that must be
+//               added before close_primitive() may legally be called.
+////////////////////////////////////////////////////////////////////
+int qpGeomPoints::
+get_min_num_vertices_per_primitive() const {
+  return 1;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPoints::draw
 //       Access: Public, Virtual

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

@@ -39,6 +39,7 @@ public:
   virtual PrimitiveType get_primitive_type() const;
 
   virtual int get_num_vertices_per_primitive() const;
+  virtual int get_min_num_vertices_per_primitive() const;
 
 public:
   virtual void draw(GraphicsStateGuardianBase *gsg) const;

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

@@ -462,6 +462,19 @@ get_num_bytes() const {
     cdata->_ends.size() * sizeof(int) + sizeof(qpGeomPrimitive);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: qpGeomPrimitive::check_valid
+//       Access: Published
+//  Description: Verifies that the primitive only references vertices
+//               that actually exist within the indicated
+//               GeomVertexData.  Returns true if the primitive
+//               appears to be valid, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool qpGeomPrimitive::
+check_valid(const qpGeomVertexData *vertex_data) const {
+  return get_max_vertex() < vertex_data->get_num_vertices();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: qpGeomPrimitive::output
 //       Access: Published, Virtual

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

@@ -139,6 +139,8 @@ PUBLISHED:
   INLINE int get_data_size_bytes() const;
   INLINE UpdateSeq get_modified() const;
 
+  bool check_valid(const qpGeomVertexData *vertex_data) const;
+
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level) const;
 

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

@@ -590,6 +590,9 @@ convert_to(const qpGeomVertexFormat *new_format) const {
 //       Access: Published
 //  Description: Returns a new GeomVertexData object with the color
 //               table modified in-place to apply the indicated scale.
+//
+//               If the vertex data does not include a color column, a
+//               new one will not be added.
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomVertexData) qpGeomVertexData::
 scale_color(const LVecBase4f &color_scale) const {
@@ -665,6 +668,9 @@ scale_color(const LVecBase4f &color_scale, int num_components,
 //       Access: Published
 //  Description: Returns a new GeomVertexData object with the color
 //               data modified in-place with the new value.
+//
+//               If the vertex data does not include a color column, a
+//               new one will not be added.
 ////////////////////////////////////////////////////////////////////
 CPT(qpGeomVertexData) qpGeomVertexData::
 set_color(const Colorf &color) const {

+ 73 - 27
panda/src/grutil/cardMaker.cxx

@@ -22,6 +22,9 @@
 #include "transformState.h"
 #include "colorAttrib.h"
 #include "sceneGraphReducer.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 
 ////////////////////////////////////////////////////////////////////
@@ -55,39 +58,82 @@ generate() {
   }
 
   PT(GeomNode) gnode = new GeomNode(get_name());
-  Geom *geom = new GeomTristrip;
-  gnode->add_geom(geom);
 
   float left = _frame[0];
   float right = _frame[1];
   float bottom = _frame[2];
   float top = _frame[3];
 
-  PTA_int lengths=PTA_int::empty_array(0);
-  lengths.push_back(4);
-
-  PTA_Vertexf verts;
-  verts.push_back(Vertexf::rfu(left, 0.0f, top));
-  verts.push_back(Vertexf::rfu(left, 0.0f, bottom));
-  verts.push_back(Vertexf::rfu(right, 0.0f, top));
-  verts.push_back(Vertexf::rfu(right, 0.0f, bottom));
-
-  geom->set_num_prims(1);
-  geom->set_lengths(lengths);
-
-  geom->set_coords(verts);
-
-  PTA_Colorf colors;
-  colors.push_back(_color);
-  geom->set_colors(colors, G_OVERALL);
-
-  if (_has_uvs) {
-    PTA_TexCoordf uvs;
-    uvs.push_back(TexCoordf(_ll[0], _ur[1]));
-    uvs.push_back(TexCoordf(_ll[0], _ll[1]));
-    uvs.push_back(TexCoordf(_ur[0], _ur[1]));
-    uvs.push_back(TexCoordf(_ur[0], _ll[1]));
-    geom->set_texcoords(uvs, G_PER_VERTEX);
+  if (use_qpgeom) {
+    CPT(qpGeomVertexFormat) format;
+    if (_has_uvs) {
+      format = qpGeomVertexFormat::get_v3cpt2();
+    } else {
+      format = qpGeomVertexFormat::get_v3cp();
+    }
+
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("card", format, qpGeomUsageHint::UH_static);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+
+    vertex.add_data3f(Vertexf::rfu(left, 0.0f, top));
+    vertex.add_data3f(Vertexf::rfu(left, 0.0f, bottom));
+    vertex.add_data3f(Vertexf::rfu(right, 0.0f, top));
+    vertex.add_data3f(Vertexf::rfu(right, 0.0f, bottom));
+
+    color.add_data4f(_color);
+    color.add_data4f(_color);
+    color.add_data4f(_color);
+    color.add_data4f(_color);
+
+    if (_has_uvs) {
+      qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+      texcoord.add_data2f(_ll[0], _ur[1]);
+      texcoord.add_data2f(_ll[0], _ll[1]);
+      texcoord.add_data2f(_ur[0], _ur[1]);
+      texcoord.add_data2f(_ur[0], _ll[1]);
+    }
+
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    strip->add_next_vertices(4);
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    gnode->add_geom(geom);
+
+  } else {
+    Geom *geom = new GeomTristrip;
+    gnode->add_geom(geom);
+
+    PTA_int lengths = PTA_int::empty_array(0);
+    lengths.push_back(4);
+    
+    PTA_Vertexf verts;
+    verts.push_back(Vertexf::rfu(left, 0.0f, top));
+    verts.push_back(Vertexf::rfu(left, 0.0f, bottom));
+    verts.push_back(Vertexf::rfu(right, 0.0f, top));
+    verts.push_back(Vertexf::rfu(right, 0.0f, bottom));
+    
+    geom->set_num_prims(1);
+    geom->set_lengths(lengths);
+    
+    geom->set_coords(verts);
+    
+    PTA_Colorf colors;
+    colors.push_back(_color);
+    geom->set_colors(colors, G_OVERALL);
+    
+    if (_has_uvs) {
+      PTA_TexCoordf uvs;
+      uvs.push_back(TexCoordf(_ll[0], _ur[1]));
+      uvs.push_back(TexCoordf(_ll[0], _ll[1]));
+      uvs.push_back(TexCoordf(_ur[0], _ur[1]));
+      uvs.push_back(TexCoordf(_ur[0], _ll[1]));
+      geom->set_texcoords(uvs, G_PER_VERTEX);
+    }
   }
   
   return gnode.p();

+ 5 - 6
panda/src/grutil/lineSegs.I

@@ -133,15 +133,14 @@ draw_to(float x, float y, float z) {
 //               created with the color and thickness established by
 //               calls to set_color() and set_thick().
 //
-//               If frame_accurate is true, the line segments will be
-//               created as a frame-accurate index, so that later
-//               calls to set_vertex or set_vertex_color will be
-//               visually correct.
+//               If dynamic is true, the line segments will be created
+//               with the dynamic Geom setting, optimizing them for
+//               runtime vertex animation.
 ////////////////////////////////////////////////////////////////////
 INLINE GeomNode *LineSegs::
-create(bool frame_accurate) {
+create(bool dynamic) {
   GeomNode *gnode = new GeomNode(get_name());
-  return create(gnode, frame_accurate);
+  return create(gnode, dynamic);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 123 - 64
panda/src/grutil/lineSegs.cxx

@@ -19,6 +19,10 @@
 #include "lineSegs.h"
 #include "renderState.h"
 #include "renderModeAttrib.h"
+#include "qpgeom.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomPoints.h"
+#include "qpgeomVertexWriter.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: LineSegs::Constructor
@@ -140,86 +144,141 @@ get_current_position() {
 //               thickness established by calls to set_color() and
 //               set_thick().
 //
-//               If frame_accurate is true, the line segments will be
-//               created as a frame-accurate index, so that later
-//               calls to set_vertex or set_vertex_color will be
-//               visually correct.
+//               If dynamic is true, the line segments will be created
+//               with the dynamic Geom setting, optimizing them for
+//               runtime vertex animation.
 ////////////////////////////////////////////////////////////////////
 GeomNode *LineSegs::
-create(GeomNode *previous, bool) {
+create(GeomNode *previous, bool dynamic) {
   if (!_list.empty()) {
     _created_verts.clear();
     _created_colors.clear();
+    _created_data = NULL;
+      
+    CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _thick);
+    CPT(RenderState) state = RenderState::make(thick);
 
-    // One array each for the indices into these arrays for points
-    // and lines, and one for our line-segment lengths array.
-    PTA_ushort point_index;
-    PTA_ushort line_index;
-    PTA_int lengths;
+    if (use_qpgeom) {
+      PT(qpGeomVertexData) vdata = new qpGeomVertexData
+        ("lineSegs", qpGeomVertexFormat::get_v3cp(),
+         dynamic ? qpGeomUsageHint::UH_dynamic : qpGeomUsageHint::UH_static);
+      qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+      qpGeomVertexWriter color(vdata, InternalName::get_color());
 
-    // Now fill up the arrays.
-    int v = 0;
-    LineList::const_iterator ll;
-    SegmentList::const_iterator sl;
+      PT(qpGeomLinestrips) lines = new qpGeomLinestrips(qpGeomUsageHint::UH_static);
+      PT(qpGeomPoints) points = new qpGeomPoints(qpGeomUsageHint::UH_static);
 
-    for (ll = _list.begin(); ll != _list.end(); ll++) {
-      const SegmentList &segs = (*ll);
+      int v = 0;
+      LineList::const_iterator ll;
+      SegmentList::const_iterator sl;
 
-      if (segs.size() < 2) {
-        point_index.push_back(v);
-      } else {
-        lengths.push_back(segs.size());
-      }
+      for (ll = _list.begin(); ll != _list.end(); ll++) {
+        const SegmentList &segs = (*ll);
+        
+        if (segs.size() < 2) {
+          // A segment of length 1 is just a point.
+          for (sl = segs.begin(); sl != segs.end(); sl++) {
+            points->add_vertex(v);
+            vertex.add_data3f((*sl)._point);
+            color.add_data4f((*sl)._color);
+            v++;
+          }
+          points->close_primitive();
 
-      for (sl = segs.begin(); sl != segs.end(); sl++) {
-        if (segs.size() >= 2) {
-          line_index.push_back(v);
+        } else {
+          // A segment of length 2 or more is a line segment or
+          // segments.
+          for (sl = segs.begin(); sl != segs.end(); sl++) {
+            lines->add_vertex(v);
+            vertex.add_data3f((*sl)._point);
+            color.add_data4f((*sl)._color);
+            v++;
+          }
+          lines->close_primitive();
         }
-        _created_verts.push_back((*sl)._point);
-        _created_colors.push_back((*sl)._color);
-        v++;
-        nassertr(v == (int)_created_verts.size(), previous);
       }
-    }
 
-    CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _thick);
-    CPT(RenderState) state = RenderState::make(thick);
-
-    // Now create the lines.
-    if (line_index.size() > 0) {
-      // Create a new Geom and add the line segments.
-      Geom *geom;
-      if (line_index.size() <= 2) {
-        // Here's a special case: just one line segment.
-        GeomLine *geom_line = new GeomLine;
-        geom_line->set_num_prims(1);
-        geom = geom_line;
-
-      } else {
-        // The more normal case: multiple line segments, connected
-        // end-to-end like a series of linestrips.
-        GeomLinestrip *geom_linestrip = new GeomLinestrip;
-        geom_linestrip->set_num_prims(lengths.size());
-        geom_linestrip->set_lengths(lengths);
-        geom = geom_linestrip;
+      if (lines->get_num_vertices() != 0) {
+        PT(qpGeom) geom = new qpGeom;
+        geom->set_vertex_data(vdata);
+        geom->add_primitive(lines);
+        previous->add_geom(geom, state);
+      }
+      if (points->get_num_vertices() != 0) {
+        PT(qpGeom) geom = new qpGeom;
+        geom->set_vertex_data(vdata);
+        geom->add_primitive(points);
+        previous->add_geom(geom, state);
       }
 
-      geom->set_colors(_created_colors, G_PER_VERTEX, line_index);
-      geom->set_coords(_created_verts, line_index);
-
-      previous->add_geom(geom, state);
-    }
-
-    // And now create the points.
-    if (point_index.size() > 0) {
-      // Create a new Geom and add the points.
-      GeomPoint *geom = new GeomPoint;
-
-      geom->set_num_prims(point_index.size());
-      geom->set_colors(_created_colors, G_PER_VERTEX, point_index);
-      geom->set_coords(_created_verts, point_index);
+    } else {
+      // One array each for the indices into these arrays for points
+      // and lines, and one for our line-segment lengths array.
+      PTA_ushort point_index;
+      PTA_ushort line_index;
+      PTA_int lengths;
+      
+      // Now fill up the arrays.
+      int v = 0;
+      LineList::const_iterator ll;
+      SegmentList::const_iterator sl;
+      
+      for (ll = _list.begin(); ll != _list.end(); ll++) {
+        const SegmentList &segs = (*ll);
+        
+        if (segs.size() < 2) {
+          point_index.push_back(v);
+        } else {
+          lengths.push_back(segs.size());
+        }
+        
+        for (sl = segs.begin(); sl != segs.end(); sl++) {
+          if (segs.size() >= 2) {
+            line_index.push_back(v);
+          }
+          _created_verts.push_back((*sl)._point);
+          _created_colors.push_back((*sl)._color);
+          v++;
+          nassertr(v == (int)_created_verts.size(), previous);
+        }
+      }
+      
+      // Now create the lines.
+      if (line_index.size() > 0) {
+        // Create a new Geom and add the line segments.
+        Geom *geom;
+        if (line_index.size() <= 2) {
+          // Here's a special case: just one line segment.
+          GeomLine *geom_line = new GeomLine;
+          geom_line->set_num_prims(1);
+          geom = geom_line;
+          
+        } else {
+          // The more normal case: multiple line segments, connected
+          // end-to-end like a series of linestrips.
+          GeomLinestrip *geom_linestrip = new GeomLinestrip;
+          geom_linestrip->set_num_prims(lengths.size());
+          geom_linestrip->set_lengths(lengths);
+          geom = geom_linestrip;
+        }
+        
+        geom->set_colors(_created_colors, G_PER_VERTEX, line_index);
+        geom->set_coords(_created_verts, line_index);
+        
+        previous->add_geom(geom, state);
+      }
 
-      previous->add_geom(geom, state);
+      // And now create the points.
+      if (point_index.size() > 0) {
+        // Create a new Geom and add the points.
+        GeomPoint *geom = new GeomPoint;
+        
+        geom->set_num_prims(point_index.size());
+        geom->set_colors(_created_colors, G_PER_VERTEX, point_index);
+        geom->set_coords(_created_verts, point_index);
+        
+        previous->add_geom(geom, state);
+      }
     }
 
     // And reset for next time.

+ 4 - 2
panda/src/grutil/lineSegs.h

@@ -27,6 +27,7 @@
 #include "geomLine.h"
 #include "geomLinestrip.h"
 #include "geomNode.h"
+#include "qpgeomVertexData.h"
 #include "namable.h"
 
 #include "pvector.h"
@@ -58,8 +59,8 @@ PUBLISHED:
   const Vertexf &get_current_position();
   bool is_empty();
 
-  INLINE GeomNode *create(bool frame_accurate = false);
-  GeomNode *create(GeomNode *previous, bool frame_accurate = false);
+  INLINE GeomNode *create(bool dynamic = false);
+  GeomNode *create(GeomNode *previous, bool dynamic = false);
 
   // Functions to move the line vertices after they have been created.
   INLINE int get_num_vertices() const;
@@ -93,6 +94,7 @@ private:
 
   PTA_Vertexf _created_verts;
   PTA_Colorf _created_colors;
+  PT(qpGeomVertexData) _created_data;
 };
 
 #include "lineSegs.I"

+ 70 - 17
panda/src/grutil/multitexReducer.cxx

@@ -37,6 +37,9 @@
 #include "config_grutil.h"
 #include "config_gobj.h"
 #include "dcast.h"
+#include "qpgeom.h"
+#include "qpgeomVertexWriter.h"
+#include "qpgeomVertexReader.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: MultitexReducer::Constructor
@@ -804,25 +807,39 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
   GeomList::const_iterator gi;
   for (gi = geom_list.begin(); gi != geom_list.end(); ++gi) {
     const GeomInfo &geom_info = (*gi);
-    
-    PT(Geom) geom = 
-      geom_info._geom_node->get_geom(geom_info._index)->make_copy();
+    const Geom *orig_geom = geom_info._geom_node->get_geom(geom_info._index);
+
+    if (orig_geom->is_of_type(qpGeom::get_class_type())) {
+      PT(qpGeom) geom = new qpGeom(*DCAST(qpGeom, orig_geom));
+      PT(qpGeomVertexData) vdata = geom->modify_vertex_data();
+
+      if (vdata->has_column(_target_stage->get_texcoord_name())) {
+        qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+        qpGeomVertexReader texcoord(vdata, _target_stage->get_texcoord_name());
 
-    PTA_Vertexf coords = PTA_Vertexf::empty_array(0);
-    PTA_TexCoordf texcoords = geom->get_texcoords_array(_target_stage->get_texcoord_name());
-    if (!texcoords.empty()) {
-      coords.reserve(texcoords.size());
-      for (size_t i = 0; i < texcoords.size(); i++) {
-        const TexCoordf &tc = texcoords[i];
-        Vertexf v(tc[0], 0.0f, tc[1]);
-        coords.push_back(v);
+        while (!texcoord.is_at_end()) {
+          const LVecBase2f &tc = texcoord.get_data2f();
+          vertex.set_data3f(tc[0], 0.0f, tc[1]);
+        }
       }
-      
-      geom->set_coords(coords, geom->get_texcoords_index(_target_stage->get_texcoord_name()));
-      if (texcoord_name != (const InternalName *)NULL) {
-        geom->set_texcoords(InternalName::get_texcoord(),
-                            geom->get_texcoords_array(texcoord_name),
-                            geom->get_texcoords_index(texcoord_name));
+
+      if (texcoord_name != (const InternalName *)NULL &&
+          texcoord_name != InternalName::get_texcoord()) {
+        // Copy the texture coordinates from the indicated name over
+        // to the default name.
+        const qpGeomVertexColumn *column = 
+          vdata->get_format()->get_column(texcoord_name);
+        vdata = vdata->replace_column
+          (InternalName::get_texcoord(), column->get_num_components(),
+           column->get_numeric_type(), column->get_contents(),
+           qpGeomUsageHint::UH_stream, true);
+        geom->set_vertex_data(vdata);
+
+        qpGeomVertexReader from(vdata, texcoord_name);
+        qpGeomVertexWriter to(vdata, InternalName::get_texcoord());
+        while (!from.is_at_end()) {
+          to.add_data2f(from.get_data2f());
+        }
       }
 
       CPT(RenderState) geom_state = RenderState::make_empty();
@@ -839,6 +856,42 @@ transfer_geom(GeomNode *geom_node, const InternalName *texcoord_name,
       }
       
       geom_node->add_geom(geom, geom_state);
+
+    } else {
+      PT(Geom) geom = orig_geom->make_copy();
+
+      PTA_Vertexf coords = PTA_Vertexf::empty_array(0);
+      PTA_TexCoordf texcoords = geom->get_texcoords_array(_target_stage->get_texcoord_name());
+      if (!texcoords.empty()) {
+        coords.reserve(texcoords.size());
+        for (size_t i = 0; i < texcoords.size(); i++) {
+          const TexCoordf &tc = texcoords[i];
+          Vertexf v(tc[0], 0.0f, tc[1]);
+          coords.push_back(v);
+        }
+      
+        geom->set_coords(coords, geom->get_texcoords_index(_target_stage->get_texcoord_name()));
+        if (texcoord_name != (const InternalName *)NULL) {
+          geom->set_texcoords(InternalName::get_texcoord(),
+                              geom->get_texcoords_array(texcoord_name),
+                              geom->get_texcoords_index(texcoord_name));
+        }
+
+        CPT(RenderState) geom_state = RenderState::make_empty();
+        if (preserve_color) {
+          // Be sure to preserve whatever colors are on the geom.
+          const RenderAttrib *ca = geom_info._geom_net_state->get_attrib(ColorAttrib::get_class_type());
+          if (ca != (const RenderAttrib *)NULL) {
+            geom_state = geom_state->add_attrib(ca);
+          }
+          const RenderAttrib *csa = geom_info._geom_net_state->get_attrib(ColorScaleAttrib::get_class_type());
+          if (csa != (const RenderAttrib *)NULL) {
+            geom_state = geom_state->add_attrib(csa);
+          }
+        }
+      
+        geom_node->add_geom(geom, geom_state);
+      }
     }
   }
 }

+ 4 - 0
panda/src/parametrics/ropeNode.cxx

@@ -30,6 +30,10 @@
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "pStatTimer.h"
+#include "qpgeom.h"
+#include "qpgeomLinestrips.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle RopeNode::_type_handle;
 

+ 130 - 61
panda/src/parametrics/sheetNode.cxx

@@ -27,6 +27,9 @@
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "pStatTimer.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 TypeHandle SheetNode::_type_handle;
 
@@ -261,82 +264,148 @@ do_recompute_bound(const NodePath &rel_to) {
 ////////////////////////////////////////////////////////////////////
 void SheetNode::
 render_sheet(CullTraverser *trav, CullTraverserData &data, 
-              NurbsSurfaceResult *result) {
+             NurbsSurfaceResult *result) {
   bool use_vertex_color = get_use_vertex_color();
 
-  PTA_Vertexf verts;
-  PTA_Normalf normals;
-  PTA_TexCoordf uvs;
-  PTA_Colorf colors;
-  PTA_int lengths;
-
-  // We define a series of triangle strips, parallel to the V
-  // direction.
-
   int num_u_segments = result->get_num_u_segments();
   int num_v_segments = result->get_num_v_segments();
   int num_u_verts = get_num_u_subdiv() + 1;
   int num_v_verts = get_num_v_subdiv() + 1;
 
-  for (int ui = 0; ui < num_u_segments; ui++) {
-    for (int uni = 0; uni < num_u_verts; uni++) {
-      float u0 = (float)uni / (float)num_u_verts;
-      float u1 = (float)(uni + 1) / (float)num_u_verts;
-      float u0_tc = result->get_segment_u(ui, u0);
-      float u1_tc = result->get_segment_u(ui, u1);
-
-      for (int vi = 0; vi < num_v_segments; vi++) {
-        for (int vni = 0; vni < num_v_verts; vni++) {
-          float v = (float)vni / (float)(num_v_verts - 1);
-          float v_tc = result->get_segment_v(vi, v);
-
-          LPoint3f point;
-          LVector3f normal;
-          result->eval_segment_point(ui, vi, u0, v, point);
-          result->eval_segment_normal(ui, vi, u0, v, normal);
-          verts.push_back(point);
-          normals.push_back(normal);
-          uvs.push_back(TexCoordf(u0_tc, v_tc));
-
-          result->eval_segment_point(ui, vi, u1, v, point);
-          result->eval_segment_normal(ui, vi, u1, v, normal);
-          verts.push_back(point);
-          normals.push_back(normal);
-          uvs.push_back(TexCoordf(u1_tc, v_tc));
-
-          if (use_vertex_color) {
-            Colorf c0, c1;
-            result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4);
-            result->eval_segment_extended_points(ui, vi, u1, v, 0, &c1[0], 4);
-
-            colors.push_back(c0);
-            colors.push_back(c1);
+  if (use_qpgeom) {
+    CPT(qpGeomVertexFormat) format;
+    if (use_vertex_color) {
+      format = qpGeomVertexFormat::get_v3n3cpt2();
+    } else {
+      format = qpGeomVertexFormat::get_v3n3t2();
+    }
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("sheet", format, qpGeomUsageHint::UH_stream);
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter normal(vdata, InternalName::get_normal());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+    qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_stream);
+    for (int ui = 0; ui < num_u_segments; ui++) {
+      for (int uni = 0; uni < num_u_verts; uni++) {
+        float u0 = (float)uni / (float)num_u_verts;
+        float u1 = (float)(uni + 1) / (float)num_u_verts;
+        float u0_tc = result->get_segment_u(ui, u0);
+        float u1_tc = result->get_segment_u(ui, u1);
+
+        for (int vi = 0; vi < num_v_segments; vi++) {
+          for (int vni = 0; vni < num_v_verts; vni++) {
+            float v = (float)vni / (float)(num_v_verts - 1);
+            float v_tc = result->get_segment_v(vi, v);
+
+            LPoint3f point;
+            LVector3f norm;
+            result->eval_segment_point(ui, vi, u0, v, point);
+            result->eval_segment_normal(ui, vi, u0, v, norm);
+            vertex.add_data3f(point);
+            normal.add_data3f(norm);
+            texcoord.add_data2f(u0_tc, v_tc);
+
+            result->eval_segment_point(ui, vi, u1, v, point);
+            result->eval_segment_normal(ui, vi, u1, v, norm);
+            vertex.add_data3f(point);
+            normal.add_data3f(norm);
+            texcoord.add_data2f(u1_tc, v_tc);
+
+            if (use_vertex_color) {
+              Colorf c0, c1;
+              result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4);
+              result->eval_segment_extended_points(ui, vi, u1, v, 0, &c1[0], 4);
+
+              color.add_data4f(c0);
+              color.add_data4f(c1);
+            }
           }
+          strip->add_next_vertices(num_v_verts * 2);
+          strip->close_primitive();
         }
-        lengths.push_back(num_v_verts * 2);
       }
     }
-  }
 
-  colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-  
-  PT(GeomTristrip) geom = new GeomTristrip;
-  geom->set_num_prims(lengths.size());
-  geom->set_coords(verts);
-  geom->set_normals(normals, G_PER_VERTEX);
-  geom->set_texcoords(uvs, G_PER_VERTEX);
-
-  if (use_vertex_color) {
-    geom->set_colors(colors, G_PER_VERTEX);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    CullableObject *object = new CullableObject(geom, data._state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object);
+
   } else {
+    PTA_Vertexf verts;
+    PTA_Normalf normals;
+    PTA_TexCoordf uvs;
+    PTA_Colorf colors;
+    PTA_int lengths;
+
+    // We define a series of triangle strips, parallel to the V
+    // direction.
+
+    for (int ui = 0; ui < num_u_segments; ui++) {
+      for (int uni = 0; uni < num_u_verts; uni++) {
+        float u0 = (float)uni / (float)num_u_verts;
+        float u1 = (float)(uni + 1) / (float)num_u_verts;
+        float u0_tc = result->get_segment_u(ui, u0);
+        float u1_tc = result->get_segment_u(ui, u1);
+
+        for (int vi = 0; vi < num_v_segments; vi++) {
+          for (int vni = 0; vni < num_v_verts; vni++) {
+            float v = (float)vni / (float)(num_v_verts - 1);
+            float v_tc = result->get_segment_v(vi, v);
+
+            LPoint3f point;
+            LVector3f normal;
+            result->eval_segment_point(ui, vi, u0, v, point);
+            result->eval_segment_normal(ui, vi, u0, v, normal);
+            verts.push_back(point);
+            normals.push_back(normal);
+            uvs.push_back(TexCoordf(u0_tc, v_tc));
+
+            result->eval_segment_point(ui, vi, u1, v, point);
+            result->eval_segment_normal(ui, vi, u1, v, normal);
+            verts.push_back(point);
+            normals.push_back(normal);
+            uvs.push_back(TexCoordf(u1_tc, v_tc));
+
+            if (use_vertex_color) {
+              Colorf c0, c1;
+              result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4);
+              result->eval_segment_extended_points(ui, vi, u1, v, 0, &c1[0], 4);
+
+              colors.push_back(c0);
+              colors.push_back(c1);
+            }
+          }
+          lengths.push_back(num_v_verts * 2);
+        }
+      }
+    }
+
     colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
-    geom->set_colors(colors, G_OVERALL);
-  }
-  geom->set_lengths(lengths);
   
-  CullableObject *object = new CullableObject(geom, data._state,
-                                              data._render_transform);
-  trav->get_cull_handler()->record_object(object);
+    PT(GeomTristrip) geom = new GeomTristrip;
+    geom->set_num_prims(lengths.size());
+    geom->set_coords(verts);
+    geom->set_normals(normals, G_PER_VERTEX);
+    geom->set_texcoords(uvs, G_PER_VERTEX);
+
+    if (use_vertex_color) {
+      geom->set_colors(colors, G_PER_VERTEX);
+    } else {
+      colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
+      geom->set_colors(colors, G_OVERALL);
+    }
+    geom->set_lengths(lengths);
+  
+    CullableObject *object = new CullableObject(geom, data._state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////

+ 63 - 9
panda/src/pgraph/cullTraverser.cxx

@@ -33,6 +33,9 @@
 #include "boundingHexahedron.h"
 #include "geomSphere.h"
 #include "portalClipper.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 PStatCollector CullTraverser::_nodes_pcollector("Nodes");
 PStatCollector CullTraverser::_geom_nodes_pcollector("Nodes:GeomNodes");
@@ -293,15 +296,47 @@ make_bounds_viz(const BoundingVolume &vol) {
 
   } else if (vol.is_of_type(BoundingSphere::get_class_type())) {
     const BoundingSphere *sphere = DCAST(BoundingSphere, &vol);
-    
-    geom = new GeomSphere;
-    PTA_Vertexf verts;
-    LPoint3f center = sphere->get_center();
-    verts.push_back(center);
-    center[0] += sphere->get_radius();
-    verts.push_back(center);
-    geom->set_coords(verts);
-    geom->set_num_prims(1);
+
+    if (use_qpgeom) {
+      static const int num_slices = 16;
+      static const int num_stacks = 8;
+
+      PT(qpGeomVertexData) vdata = new qpGeomVertexData
+        ("collision", qpGeomVertexFormat::get_v3(),
+         qpGeomUsageHint::UH_stream);
+      qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+      
+      PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_stream);
+      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(sphere, 0.0, longitude0));
+        for (int st = 1; st < num_stacks; ++st) {
+          float latitude = (float)st / (float)num_stacks;
+          vertex.add_data3f(compute_point(sphere, latitude, longitude0));
+          vertex.add_data3f(compute_point(sphere, latitude, longitude1));
+        }
+        vertex.add_data3f(compute_point(sphere, 1.0, longitude0));
+        
+        strip->add_next_vertices(num_stacks * 2);
+        strip->close_primitive();
+      }
+      
+      PT(qpGeom) qpgeom = new qpGeom;
+      qpgeom->set_vertex_data(vdata);
+      qpgeom->add_primitive(strip);
+      geom = qpgeom.p();
+
+    } else {
+      geom = new GeomSphere;
+      PTA_Vertexf verts;
+      LPoint3f center = sphere->get_center();
+      verts.push_back(center);
+      center[0] += sphere->get_radius();
+      verts.push_back(center);
+      geom->set_coords(verts);
+      geom->set_num_prims(1);
+    }
     
   } else {
     pgraph_cat.warning()
@@ -312,6 +347,25 @@ make_bounds_viz(const BoundingVolume &vol) {
   return geom;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: CullTraverser::compute_point
+//       Access: Private, Static
+//  Description: Returns a point on the surface of the sphere.
+//               latitude and longitude range from 0.0 to 1.0.  
+////////////////////////////////////////////////////////////////////
+Vertexf CullTraverser::
+compute_point(const BoundingSphere *sphere, 
+              float latitude, float longitude) {
+  float s1, c1;
+  csincos(latitude * MathNumbers::pi_f, &s1, &c1);
+
+  float s2, c2;
+  csincos(longitude * 2.0f * MathNumbers::pi_f, &s2, &c2);
+
+  Vertexf p(s1 * c2, s1 * s2, c1);
+  return p * sphere->get_radius() + sphere->get_center();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: CullTraverser::get_bounds_outer_viz_state
 //       Access: Private, Static

+ 2 - 0
panda/src/pgraph/cullTraverser.h

@@ -94,6 +94,8 @@ public:
 private:
   void show_bounds(CullTraverserData &data);
   PT(Geom) make_bounds_viz(const BoundingVolume &vol);
+  static Vertexf compute_point(const BoundingSphere *sphere, 
+                               float latitude, float longitude);
   CPT(RenderState) get_bounds_outer_viz_state();
   CPT(RenderState) get_bounds_inner_viz_state();
   CPT(RenderState) get_depth_offset_state();

+ 0 - 21
panda/src/pgraph/geomNode.I

@@ -121,27 +121,6 @@ set_geom_state(int n, const RenderState *state) {
   cdata->_geoms[n]._state = state;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: GeomNode::add_geom
-//       Access: Published
-//  Description: Adds a new Geom to the node.  The geom is given the
-//               indicated state (which may be
-//               RenderState::make_empty(), to completely inherit its
-//               state from the scene graph).
-//
-//               The return value is the index number of the new Geom.
-////////////////////////////////////////////////////////////////////
-INLINE int GeomNode::
-add_geom(Geom *geom, const RenderState *state) {
-  nassertr(geom != (Geom *)NULL, -1);
-  nassertr(state != (RenderState *)NULL, -1);
-  CDWriter cdata(_cycler);
-
-  cdata->_geoms.push_back(GeomEntry(geom, state));
-  mark_bound_stale();
-  return cdata->_geoms.size() - 1;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomNode::remove_geom
 //       Access: Published

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

@@ -405,6 +405,28 @@ get_legal_collide_mask() const {
   return CollideMask::all_on();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GeomNode::add_geom
+//       Access: Published
+//  Description: Adds a new Geom to the node.  The geom is given the
+//               indicated state (which may be
+//               RenderState::make_empty(), to completely inherit its
+//               state from the scene graph).
+//
+//               The return value is the index number of the new Geom.
+////////////////////////////////////////////////////////////////////
+int GeomNode::
+add_geom(Geom *geom, const RenderState *state) {
+  nassertr(geom != (Geom *)NULL, -1);
+  nassertr(geom->check_valid(), -1);
+  nassertr(state != (RenderState *)NULL, -1);
+  CDWriter cdata(_cycler);
+
+  cdata->_geoms.push_back(GeomEntry(geom, state));
+  mark_bound_stale();
+  return cdata->_geoms.size() - 1;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GeomNode::add_geoms_from
 //       Access: Published
@@ -415,15 +437,16 @@ void GeomNode::
 add_geoms_from(const GeomNode *other) {
   CDReader cdata_other(other->_cycler);
   CDWriter cdata(_cycler);
+  mark_bound_stale();
 
   Geoms::const_iterator gi;
   for (gi = cdata_other->_geoms.begin(); 
        gi != cdata_other->_geoms.end(); 
        ++gi) {
     const GeomEntry &entry = (*gi);
+    nassertv(entry._geom->check_valid());
     cdata->_geoms.push_back(entry);
   }
-  mark_bound_stale();
 }
 
 ////////////////////////////////////////////////////////////////////

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

@@ -62,7 +62,7 @@ PUBLISHED:
   INLINE const RenderState *get_geom_state(int n) const;
   INLINE void set_geom_state(int n, const RenderState *state);
 
-  INLINE int add_geom(Geom *geom, const RenderState *state = RenderState::make_empty());
+  int add_geom(Geom *geom, const RenderState *state = RenderState::make_empty());
   void add_geoms_from(const GeomNode *other);
   INLINE void remove_geom(int n);
   INLINE void remove_all_geoms();

+ 14 - 2
panda/src/pgraph/geomTransformer.cxx

@@ -324,7 +324,13 @@ set_color(Geom *geom, const Colorf &color) {
     CPT(qpGeomVertexData) &new_data = _qpfcolors[sc];
     if (new_data.is_null()) {
       // We have not yet converted these colors.  Do so now.
-      new_data = sc._vertex_data->set_color(color);
+      if (sc._vertex_data->has_column(InternalName::get_color())) {
+        new_data = sc._vertex_data->set_color(color);
+      } else {
+        new_data = sc._vertex_data->set_color
+          (color, 1, qpGeomVertexColumn::NT_packed_dabc,
+           qpGeomVertexColumn::C_color);
+      }
     }
 
     qpgeom->set_vertex_data(new_data);
@@ -399,7 +405,13 @@ transform_colors(Geom *geom, const LVecBase4f &scale) {
     CPT(qpGeomVertexData) &new_data = _qptcolors[sc];
     if (new_data.is_null()) {
       // We have not yet converted these colors.  Do so now.
-      new_data = sc._vertex_data->scale_color(scale);
+      if (sc._vertex_data->has_column(InternalName::get_color())) {
+        new_data = sc._vertex_data->scale_color(scale);
+      } else {
+        new_data = sc._vertex_data->set_color
+          (scale, 1, qpGeomVertexColumn::NT_packed_dabc,
+           qpGeomVertexColumn::C_color);
+      }
     }
 
     qpgeom->set_vertex_data(new_data);

+ 334 - 141
panda/src/pgui/pgFrameStyle.cxx

@@ -26,6 +26,10 @@
 #include "nodePath.h"
 #include "textureAttrib.h"
 #include "renderState.h"
+#include "shadeModelAttrib.h"
+#include "qpgeom.h"
+#include "qpgeomTristrips.h"
+#include "qpgeomVertexWriter.h"
 
 // Specifies the UV range of textures applied to the frame.  Maybe
 // we'll have a reason to make this a parameter of the frame style one
@@ -170,49 +174,98 @@ generate_into(const NodePath &parent, const LVecBase4f &frame) {
 PT(PandaNode) PGFrameStyle::
 generate_flat_geom(const LVecBase4f &frame) {
   PT(GeomNode) gnode = new GeomNode("flat");
-  Geom *geom = new GeomTristrip;
-  gnode->add_geom(geom);
 
   float left = frame[0];
   float right = frame[1];
   float bottom = frame[2];
   float top = frame[3];
 
-  PTA_int lengths;
-  lengths.push_back(4);
-
-  PTA_Vertexf verts;
-  verts.push_back(Vertexf(left, 0.0f, top));
-  verts.push_back(Vertexf(left, 0.0f, bottom));
-  verts.push_back(Vertexf(right, 0.0f, top));
-  verts.push_back(Vertexf(right, 0.0f, bottom));
-
-  geom->set_num_prims(1);
-  geom->set_lengths(lengths);
-
-  geom->set_coords(verts);
-
-  PTA_Colorf colors;
-  colors.push_back(_color);
-  geom->set_colors(colors, G_OVERALL);
-
-  if (has_texture()) {
-    // Generate UV's.
-    left = uv_range[0];
-    right = uv_range[1];
-    bottom = uv_range[2];
-    top = uv_range[3];
+  if (use_qpgeom) {
+    CPT(qpGeomVertexFormat) format;
+    if (has_texture()) {
+      format = qpGeomVertexFormat::get_v3cpt2();
+    } else {
+      format = qpGeomVertexFormat::get_v3cp();
+    }
+
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("PGFrame", format, 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, top);
+    vertex.add_data3f(right, 0.0f, bottom);
+
+    if (has_texture()) {
+      // Generate UV's.
+      left = uv_range[0];
+      right = uv_range[1];
+      bottom = uv_range[2];
+      top = uv_range[3];
+    
+      qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+      texcoord.add_data2f(left, top);
+      texcoord.add_data2f(left, bottom);
+      texcoord.add_data2f(right, top);
+      texcoord.add_data2f(right, bottom);
+    }
+
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    strip->add_next_vertices(4);
+    strip->close_primitive();
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+    gnode->add_geom(geom);
+
+    if (has_texture()) {
+      CPT(RenderState) state = 
+        RenderState::make(TextureAttrib::make(get_texture()));
+      gnode->set_geom_state(0, state);
+    }
+
+  } else {
+    Geom *geom = new GeomTristrip;
+    gnode->add_geom(geom);
+
+    PTA_int lengths;
+    lengths.push_back(4);
+
+    PTA_Vertexf verts;
+    verts.push_back(Vertexf(left, 0.0f, top));
+    verts.push_back(Vertexf(left, 0.0f, bottom));
+    verts.push_back(Vertexf(right, 0.0f, top));
+    verts.push_back(Vertexf(right, 0.0f, bottom));
+
+    geom->set_num_prims(1);
+    geom->set_lengths(lengths);
+
+    geom->set_coords(verts);
+
+    PTA_Colorf colors;
+    colors.push_back(_color);
+    geom->set_colors(colors, G_OVERALL);
+
+    if (has_texture()) {
+      // Generate UV's.
+      left = uv_range[0];
+      right = uv_range[1];
+      bottom = uv_range[2];
+      top = uv_range[3];
     
-    PTA_TexCoordf uvs;
-    uvs.push_back(TexCoordf(left, top));
-    uvs.push_back(TexCoordf(left, bottom));
-    uvs.push_back(TexCoordf(right, top));
-    uvs.push_back(TexCoordf(right, bottom));
-    geom->set_texcoords(uvs, G_PER_VERTEX);
-
-    CPT(RenderState) state = 
-      RenderState::make(TextureAttrib::make(get_texture()));
-    gnode->set_geom_state(0, state);
+      PTA_TexCoordf uvs;
+      uvs.push_back(TexCoordf(left, top));
+      uvs.push_back(TexCoordf(left, bottom));
+      uvs.push_back(TexCoordf(right, top));
+      uvs.push_back(TexCoordf(right, bottom));
+      geom->set_texcoords(uvs, G_PER_VERTEX);
+
+      CPT(RenderState) state = 
+        RenderState::make(TextureAttrib::make(get_texture()));
+      gnode->set_geom_state(0, state);
+    }
   }
   
   return gnode.p();
@@ -328,52 +381,109 @@ generate_bevel_geom(const LVecBase4f &frame, bool in) {
               min(_color[2] * top_color_scale, 1.0f),
               _color[3]);
 
-  // Now make the tristrips.
-  Geom *geom = new GeomTristrip;
-  gnode->add_geom(geom);
+  if (use_qpgeom) {
+    CPT(qpGeomVertexFormat) format = qpGeomVertexFormat::get_v3cp();
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("PGFrame", format, qpGeomUsageHint::UH_static);
+
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    // Tristrip 1.
+    vertex.add_data3f(right, 0.0f, bottom);
+    vertex.add_data3f(inner_right, 0.0f, inner_bottom);
+    vertex.add_data3f(left, 0.0f, bottom);
+    vertex.add_data3f(inner_left, 0.0f, inner_bottom);
+    vertex.add_data3f(left, 0.0f, top);
+    vertex.add_data3f(inner_left, 0.0f, inner_top);
+    vertex.add_data3f(right, 0.0f, top);
+    vertex.add_data3f(inner_right, 0.0f, inner_top);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+    color.add_data4f(cleft);
+    color.add_data4f(cleft);
+    color.add_data4f(ctop);
+    color.add_data4f(ctop);
+
+    strip->add_next_vertices(8);
+    strip->close_primitive();
+
+    // Tristrip 2.
+    vertex.add_data3f(right, 0.0f, bottom);
+    vertex.add_data3f(right, 0.0f, top);
+    vertex.add_data3f(inner_right, 0.0f, inner_bottom);
+    vertex.add_data3f(inner_right, 0.0f, inner_top);
+    vertex.add_data3f(inner_left, 0.0f, inner_bottom);
+    vertex.add_data3f(inner_left, 0.0f, inner_top);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(_color);
+    color.add_data4f(_color);
+
+    strip->add_next_vertices(6);
+    strip->close_primitive();
+    strip->set_shade_model(qpGeomPrimitive::SM_flat_last_vertex);
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    CPT(RenderState) flat_state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
+    gnode->add_geom(geom, flat_state);
+
+  } else {
+    // Now make the tristrips.
+    Geom *geom = new GeomTristrip;
+    gnode->add_geom(geom);
     
-  PTA_int lengths;
-  PTA_Vertexf verts;
-  PTA_Colorf colors;
+    PTA_int lengths;
+    PTA_Vertexf verts;
+    PTA_Colorf colors;
 
-  // Tristrip 1.
-  lengths.push_back(8);
+    // Tristrip 1.
+    lengths.push_back(8);
     
-  verts.push_back(Vertexf(right, 0.0f, bottom));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(left, 0.0f, bottom));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(left, 0.0f, top));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
-  verts.push_back(Vertexf(right, 0.0f, top));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
+    verts.push_back(Vertexf(right, 0.0f, bottom));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(left, 0.0f, bottom));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(left, 0.0f, top));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
+    verts.push_back(Vertexf(right, 0.0f, top));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
   
-  colors.push_back(cbottom);
-  colors.push_back(cbottom);
-  colors.push_back(cleft);
-  colors.push_back(cleft);
-  colors.push_back(ctop);
-  colors.push_back(ctop);
-
-  // Tristrip 2.
-  lengths.push_back(6);
-
-  verts.push_back(Vertexf(right, 0.0f, bottom));
-  verts.push_back(Vertexf(right, 0.0f, top));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
-
-  colors.push_back(cright);
-  colors.push_back(cright);
-  colors.push_back(_color);
-  colors.push_back(_color);
-
-  geom->set_num_prims(2);
-  geom->set_lengths(lengths);
-  geom->set_coords(verts);
-  geom->set_colors(colors, G_PER_COMPONENT);
+    colors.push_back(cbottom);
+    colors.push_back(cbottom);
+    colors.push_back(cleft);
+    colors.push_back(cleft);
+    colors.push_back(ctop);
+    colors.push_back(ctop);
+
+    // Tristrip 2.
+    lengths.push_back(6);
+
+    verts.push_back(Vertexf(right, 0.0f, bottom));
+    verts.push_back(Vertexf(right, 0.0f, top));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
+
+    colors.push_back(cright);
+    colors.push_back(cright);
+    colors.push_back(_color);
+    colors.push_back(_color);
+
+    geom->set_num_prims(2);
+    geom->set_lengths(lengths);
+    geom->set_coords(verts);
+    geom->set_colors(colors, G_PER_COMPONENT);
+  }
 
   // For now, beveled and grooved geoms don't support textures.  Easy
   // to add if anyone really wants this.
@@ -537,75 +647,158 @@ generate_groove_geom(const LVecBase4f &frame, bool in) {
               min(_color[2] * top_color_scale, 1.0f),
               _color[3]);
 
-  // Now make the tristrips.
-  Geom *geom = new GeomTristrip;
-  gnode->add_geom(geom);
+  if (use_qpgeom) {
+    CPT(qpGeomVertexFormat) format = qpGeomVertexFormat::get_v3cp();
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("PGFrame", format, qpGeomUsageHint::UH_static);
+
+    qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+    qpGeomVertexWriter color(vdata, InternalName::get_color());
+
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_static);
+    // Tristrip 1.
+    vertex.add_data3f(right, 0.0f, bottom);
+    vertex.add_data3f(mid_right, 0.0f, mid_bottom);
+    vertex.add_data3f(left, 0.0f, bottom);
+    vertex.add_data3f(mid_left, 0.0f, mid_bottom);
+    vertex.add_data3f(left, 0.0f, top);
+    vertex.add_data3f(mid_left, 0.0f, mid_top);
+    vertex.add_data3f(right, 0.0f, top);
+    vertex.add_data3f(mid_right, 0.0f, mid_top);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+    color.add_data4f(cleft);
+    color.add_data4f(cleft);
+    color.add_data4f(ctop);
+    color.add_data4f(ctop);
+
+    strip->add_next_vertices(8);
+    strip->close_primitive();
+
+    // Tristrip 2.
+    vertex.add_data3f(mid_right, 0.0f, mid_bottom);
+    vertex.add_data3f(inner_right, 0.0f, inner_bottom);
+    vertex.add_data3f(mid_left, 0.0f, mid_bottom);
+    vertex.add_data3f(inner_left, 0.0f, inner_bottom);
+    vertex.add_data3f(mid_left, 0.0f, mid_top);
+    vertex.add_data3f(inner_left, 0.0f, inner_top);
+    vertex.add_data3f(mid_right, 0.0f, mid_top);
+    vertex.add_data3f(inner_right, 0.0f, inner_top);
+    color.add_data4f(ctop);
+    color.add_data4f(ctop);
+    color.add_data4f(ctop);
+    color.add_data4f(ctop);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(cbottom);
+    color.add_data4f(cbottom);
+
+    strip->add_next_vertices(8);
+    strip->close_primitive();
+
+    // Tristrip 3.
+    vertex.add_data3f(right, 0.0f, bottom);
+    vertex.add_data3f(right, 0.0f, top);
+    vertex.add_data3f(mid_right, 0.0f, mid_bottom);
+    vertex.add_data3f(mid_right, 0.0f, mid_top);
+    vertex.add_data3f(inner_right, 0.0f, inner_bottom);
+    vertex.add_data3f(inner_right, 0.0f, inner_top);
+    vertex.add_data3f(inner_left, 0.0f, inner_bottom);
+    vertex.add_data3f(inner_left, 0.0f, inner_top);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(cright);
+    color.add_data4f(cleft);
+    color.add_data4f(cleft);
+    color.add_data4f(_color);
+    color.add_data4f(_color);
+
+    strip->add_next_vertices(8);
+    strip->close_primitive();
+
+    strip->set_shade_model(qpGeomPrimitive::SM_flat_last_vertex);
+
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
+
+    CPT(RenderState) flat_state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
+    gnode->add_geom(geom, flat_state);
+
+  } else {
+    // Now make the tristrips.
+    Geom *geom = new GeomTristrip;
+    gnode->add_geom(geom);
     
-  PTA_int lengths;
-  PTA_Vertexf verts;
-  PTA_Colorf colors;
+    PTA_int lengths;
+    PTA_Vertexf verts;
+    PTA_Colorf colors;
 
-  // Tristrip 1.
-  lengths.push_back(8);
+    // Tristrip 1.
+    lengths.push_back(8);
     
-  verts.push_back(Vertexf(right, 0.0f, bottom));
-  verts.push_back(Vertexf(mid_right, 0.0f, mid_bottom));
-  verts.push_back(Vertexf(left, 0.0f, bottom));
-  verts.push_back(Vertexf(mid_left, 0.0f, mid_bottom));
-  verts.push_back(Vertexf(left, 0.0f, top));
-  verts.push_back(Vertexf(mid_left, 0.0f, mid_top));
-  verts.push_back(Vertexf(right, 0.0f, top));
-  verts.push_back(Vertexf(mid_right, 0.0f, mid_top));
+    verts.push_back(Vertexf(right, 0.0f, bottom));
+    verts.push_back(Vertexf(mid_right, 0.0f, mid_bottom));
+    verts.push_back(Vertexf(left, 0.0f, bottom));
+    verts.push_back(Vertexf(mid_left, 0.0f, mid_bottom));
+    verts.push_back(Vertexf(left, 0.0f, top));
+    verts.push_back(Vertexf(mid_left, 0.0f, mid_top));
+    verts.push_back(Vertexf(right, 0.0f, top));
+    verts.push_back(Vertexf(mid_right, 0.0f, mid_top));
   
-  colors.push_back(cbottom);
-  colors.push_back(cbottom);
-  colors.push_back(cleft);
-  colors.push_back(cleft);
-  colors.push_back(ctop);
-  colors.push_back(ctop);
-
-  // Tristrip 2.
-  lengths.push_back(8);
+    colors.push_back(cbottom);
+    colors.push_back(cbottom);
+    colors.push_back(cleft);
+    colors.push_back(cleft);
+    colors.push_back(ctop);
+    colors.push_back(ctop);
+
+    // Tristrip 2.
+    lengths.push_back(8);
     
-  verts.push_back(Vertexf(mid_right, 0.0f, mid_bottom));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(mid_left, 0.0f, mid_bottom));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(mid_left, 0.0f, mid_top));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
-  verts.push_back(Vertexf(mid_right, 0.0f, mid_top));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
+    verts.push_back(Vertexf(mid_right, 0.0f, mid_bottom));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(mid_left, 0.0f, mid_bottom));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(mid_left, 0.0f, mid_top));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
+    verts.push_back(Vertexf(mid_right, 0.0f, mid_top));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
   
-  colors.push_back(ctop);
-  colors.push_back(ctop);
-  colors.push_back(cright);
-  colors.push_back(cright);
-  colors.push_back(cbottom);
-  colors.push_back(cbottom);
-
-  // Tristrip 3.
-  lengths.push_back(8);
-
-  verts.push_back(Vertexf(right, 0.0f, bottom));
-  verts.push_back(Vertexf(right, 0.0f, top));
-  verts.push_back(Vertexf(mid_right, 0.0f, mid_bottom));
-  verts.push_back(Vertexf(mid_right, 0.0f, mid_top));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
-  verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
-
-  colors.push_back(cright);
-  colors.push_back(cright);
-  colors.push_back(cleft);
-  colors.push_back(cleft);
-  colors.push_back(_color);
-  colors.push_back(_color);
-
-  geom->set_num_prims(3);
-  geom->set_lengths(lengths);
-  geom->set_coords(verts);
-  geom->set_colors(colors, G_PER_COMPONENT);
+    colors.push_back(ctop);
+    colors.push_back(ctop);
+    colors.push_back(cright);
+    colors.push_back(cright);
+    colors.push_back(cbottom);
+    colors.push_back(cbottom);
+
+    // Tristrip 3.
+    lengths.push_back(8);
+
+    verts.push_back(Vertexf(right, 0.0f, bottom));
+    verts.push_back(Vertexf(right, 0.0f, top));
+    verts.push_back(Vertexf(mid_right, 0.0f, mid_bottom));
+    verts.push_back(Vertexf(mid_right, 0.0f, mid_top));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(inner_right, 0.0f, inner_top));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_bottom));
+    verts.push_back(Vertexf(inner_left, 0.0f, inner_top));
+
+    colors.push_back(cright);
+    colors.push_back(cright);
+    colors.push_back(cleft);
+    colors.push_back(cleft);
+    colors.push_back(_color);
+    colors.push_back(_color);
+
+    geom->set_num_prims(3);
+    geom->set_lengths(lengths);
+    geom->set_coords(verts);
+    geom->set_colors(colors, G_PER_COMPONENT);
+  }
 
   // For now, beveled and grooved geoms don't support textures.  Easy
   // to add if anyone really wants this.

+ 1 - 7
panda/src/text/dynamicTextGlyph.cxx

@@ -125,21 +125,15 @@ make_geom(int bitmap_top, int bitmap_left, float advance, float poly_margin,
   // Create a corresponding tristrip.
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      (string(), qpGeomVertexFormat::get_v3cpt2(),
+      (string(), qpGeomVertexFormat::get_v3t2(),
        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);

+ 3 - 3
panda/src/text/textNode.cxx

@@ -607,7 +607,7 @@ make_frame() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("text", qpGeomVertexFormat::get_v3cp(),
+      ("text", qpGeomVertexFormat::get_v3(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
 
@@ -681,7 +681,7 @@ make_card() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("text", qpGeomVertexFormat::get_v3cpt2(),
+      ("text", qpGeomVertexFormat::get_v3t2(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
@@ -766,7 +766,7 @@ make_card_with_border() {
 
   if (use_qpgeom) {
     PT(qpGeomVertexData) vdata = new qpGeomVertexData
-      ("text", qpGeomVertexFormat::get_v3cpt2(),
+      ("text", qpGeomVertexFormat::get_v3t2(),
        qpGeomUsageHint::UH_static);
     qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
     qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());