Pārlūkot izejas kodu

render RopeNode with qpgeom

David Rose 20 gadi atpakaļ
vecāks
revīzija
7ec6a915bd
2 mainītis faili ar 516 papildinājumiem un 162 dzēšanām
  1. 500 162
      panda/src/parametrics/ropeNode.cxx
  2. 16 0
      panda/src/parametrics/ropeNode.h

+ 500 - 162
panda/src/parametrics/ropeNode.cxx

@@ -252,6 +252,38 @@ recompute_internal_bound() {
   return do_recompute_bound(NodePath(this));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RopeNode::get_format
+//       Access: Private
+//  Description: Returns the appropriate GeomVertexFormat for
+//               rendering, according to the user-specified
+//               requirements.
+////////////////////////////////////////////////////////////////////
+CPT(qpGeomVertexFormat) RopeNode::
+get_format(bool support_normals) const {
+  PT(qpGeomVertexArrayFormat) array_format = new qpGeomVertexArrayFormat
+    (InternalName::get_vertex(), 3, qpGeomVertexColumn::NT_float32,
+     qpGeomVertexColumn::C_point);
+
+  if (support_normals && get_normal_mode() == NM_vertex) {
+    array_format->add_column
+      (InternalName::get_normal(), 3, qpGeomVertexColumn::NT_float32,
+       qpGeomVertexColumn::C_vector);
+  }
+  if (get_use_vertex_color()) {
+    array_format->add_column
+      (InternalName::get_color(), 1, qpGeomVertexColumn::NT_packed_dabc,
+       qpGeomVertexColumn::C_color);
+  }
+  if (get_uv_mode() != UV_none) {
+    array_format->add_column
+      (InternalName::get_texcoord(), 2, qpGeomVertexColumn::NT_float32,
+       qpGeomVertexColumn::C_texcoord);
+  }
+
+  return qpGeomVertexFormat::register_format(array_format);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::do_recompute_bound
 //       Access: Private
@@ -303,50 +335,80 @@ render_thread(CullTraverser *trav, CullTraverserData &data,
   CurveSegments curve_segments;
   get_connected_segments(curve_segments, result);
 
-  // Now we have stored one or more sequences of vertices down the
-  // center strips.  Go back through and calculate the vertices on
-  // either side.
-
-  PTA_Vertexf verts;
-  PTA_TexCoordf uvs;
-  PTA_Colorf colors;
-
-  compute_thread_vertices(verts, uvs, colors, curve_segments);
+  if (use_qpgeom) {
+    // Now we have stored one or more sequences of vertices down the
+    // center strips.  Go back through and calculate the vertices on
+    // either side.
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("rope", get_format(false), qpGeomUsageHint::UH_stream);
 
-  // Finally, build the lengths array to make them into proper
-  // line strips.
-
-  PTA_int lengths;
-  int num_prims = 0;
+    compute_thread_vertices(vdata, curve_segments);
+    
+    PT(qpGeomLinestrips) strip = new qpGeomLinestrips(qpGeomUsageHint::UH_stream);
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      strip->add_next_vertices(segment.size());
+      strip->close_primitive();
+    }
 
-  CurveSegments::const_iterator si;
-  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
-    const CurveSegment &segment = (*si);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
 
-    lengths.push_back(segment.size());
-    num_prims++;
-  }
-  
-  PT(GeomLinestrip) geom = new GeomLinestrip;
-  geom->set_num_prims(num_prims);
-  geom->set_coords(verts);
-  if (get_uv_mode() != UV_none) {
-    geom->set_texcoords(uvs, G_PER_VERTEX);
-  }
+    CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, get_thickness());
+    CPT(RenderState) state = data._state->add_attrib(thick);
+    
+    CullableObject *object = new CullableObject(geom, state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object, trav);
 
-  if (get_use_vertex_color()) {
-    geom->set_colors(colors, G_PER_VERTEX);
   } else {
-    geom->set_colors(colors, G_OVERALL);
-  }
-  geom->set_lengths(lengths);
+    // Now we have stored one or more sequences of vertices down the
+    // center strips.  Go back through and calculate the vertices on
+    // either side.
+    PTA_Vertexf verts;
+    PTA_TexCoordf uvs;
+    PTA_Colorf colors;
+    
+    compute_thread_vertices(verts, uvs, colors, curve_segments);
 
-  CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, get_thickness());
-  CPT(RenderState) state = data._state->add_attrib(thick);
-  
-  CullableObject *object = new CullableObject(geom, state,
-                                              data._render_transform);
-  trav->get_cull_handler()->record_object(object, trav);
+    // Finally, build the lengths array to make them into proper
+    // line strips.
+    
+    PTA_int lengths;
+    int num_prims = 0;
+    
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      lengths.push_back(segment.size());
+      num_prims++;
+    }
+    
+    PT(GeomLinestrip) geom = new GeomLinestrip;
+    geom->set_num_prims(num_prims);
+    geom->set_coords(verts);
+    if (get_uv_mode() != UV_none) {
+      geom->set_texcoords(uvs, G_PER_VERTEX);
+    }
+    
+    if (get_use_vertex_color()) {
+      geom->set_colors(colors, G_PER_VERTEX);
+    } else {
+      geom->set_colors(colors, G_OVERALL);
+    }
+    geom->set_lengths(lengths);
+    
+    CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, get_thickness());
+    CPT(RenderState) state = data._state->add_attrib(thick);
+    
+    CullableObject *object = new CullableObject(geom, state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object, trav);
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -365,50 +427,79 @@ render_tape(CullTraverser *trav, CullTraverserData &data,
   CurveSegments curve_segments;
   get_connected_segments(curve_segments, result);
 
-  // Now we have stored one or more sequences of vertices down the
-  // center strips.  Go back through and calculate the vertices on
-  // either side.
+  if (use_qpgeom) {
+    // Now we have stored one or more sequences of vertices down the
+    // center strips.  Go back through and calculate the vertices on
+    // either side.
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("rope", get_format(false), qpGeomUsageHint::UH_stream);
 
-  PTA_Vertexf verts;
-  PTA_TexCoordf uvs;
-  PTA_Colorf colors;
-
-  compute_billboard_vertices(verts, uvs, colors, -get_tube_up(), 
-                             curve_segments, result);
+    compute_billboard_vertices(vdata, -get_tube_up(), 
+                               curve_segments, result);
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_stream);
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      strip->add_next_vertices(segment.size() * 2);
+      strip->close_primitive();
+    }
 
-  // Finally, build the lengths array to make them into proper
-  // triangle strips.  We don't need a vindex array here, since the
-  // vertices just happened to end up in tristrip order.
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
 
-  PTA_int lengths;
-  int num_prims = 0;
+    CullableObject *object = new CullableObject(geom, data._state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object, trav);
 
-  CurveSegments::const_iterator si;
-  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
-    const CurveSegment &segment = (*si);
-
-    lengths.push_back(segment.size() * 2);
-    num_prims++;
-  }
+  } else {
+    // Now we have stored one or more sequences of vertices down the
+    // center strips.  Go back through and calculate the vertices on
+    // either side.
+    
+    PTA_Vertexf verts;
+    PTA_TexCoordf uvs;
+    PTA_Colorf colors;
+    
+    compute_billboard_vertices(verts, uvs, colors, -get_tube_up(), 
+                               curve_segments, result);
+    
+    // Finally, build the lengths array to make them into proper
+    // triangle strips.  We don't need a vindex array here, since the
+    // vertices just happened to end up in tristrip order.
+    
+    PTA_int lengths;
+    int num_prims = 0;
+    
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      lengths.push_back(segment.size() * 2);
+      num_prims++;
+    }
 
-  // And create a Geom for the rendering.
+    // And create a Geom for the rendering.
   
-  PT(Geom) geom = new GeomTristrip;
-  geom->set_num_prims(num_prims);
-  geom->set_coords(verts);
-  if (get_uv_mode() != UV_none) {
-    geom->set_texcoords(uvs, G_PER_VERTEX);
-  }
-  if (get_use_vertex_color()) {
-    geom->set_colors(colors, G_PER_VERTEX);
-  } else {
-    geom->set_colors(colors, G_OVERALL);
+    PT(Geom) geom = new GeomTristrip;
+    geom->set_num_prims(num_prims);
+    geom->set_coords(verts);
+    if (get_uv_mode() != UV_none) {
+      geom->set_texcoords(uvs, G_PER_VERTEX);
+    }
+    if (get_use_vertex_color()) {
+      geom->set_colors(colors, G_PER_VERTEX);
+    } else {
+      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, trav);
   }
-  geom->set_lengths(lengths);
-  
-  CullableObject *object = new CullableObject(geom, data._state,
-                                              data._render_transform);
-  trav->get_cull_handler()->record_object(object, trav);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -434,50 +525,79 @@ render_billboard(CullTraverser *trav, CullTraverserData &data,
   CurveSegments curve_segments;
   get_connected_segments(curve_segments, result);
 
-  // Now we have stored one or more sequences of vertices down the
-  // center strips.  Go back through and calculate the vertices on
-  // either side.
+  if (use_qpgeom) {
+    // Now we have stored one or more sequences of vertices down the
+    // center strips.  Go back through and calculate the vertices on
+    // either side.
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("rope", get_format(false), qpGeomUsageHint::UH_stream);
 
-  PTA_Vertexf verts;
-  PTA_TexCoordf uvs;
-  PTA_Colorf colors;
-
-  compute_billboard_vertices(verts, uvs, colors, camera_vec, 
-                             curve_segments, result);
-
-  // Finally, build the lengths array to make them into proper
-  // triangle strips.  We don't need a vindex array here, since the
-  // vertices just happened to end up in tristrip order.
-
-  PTA_int lengths;
-  int num_prims = 0;
+    compute_billboard_vertices(vdata, camera_vec, 
+                               curve_segments, result);
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_stream);
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      strip->add_next_vertices(segment.size() * 2);
+      strip->close_primitive();
+    }
 
-  CurveSegments::const_iterator si;
-  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
-    const CurveSegment &segment = (*si);
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
 
-    lengths.push_back(segment.size() * 2);
-    num_prims++;
-  }
+    CullableObject *object = new CullableObject(geom, data._state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object, trav);
 
-  // And create a Geom for the rendering.
-  
-  PT(Geom) geom = new GeomTristrip;
-  geom->set_num_prims(num_prims);
-  geom->set_coords(verts);
-  if (get_uv_mode() != UV_none) {
-    geom->set_texcoords(uvs, G_PER_VERTEX);
-  }
-  if (get_use_vertex_color()) {
-    geom->set_colors(colors, G_PER_VERTEX);
   } else {
-    geom->set_colors(colors, G_OVERALL);
+    // Now we have stored one or more sequences of vertices down the
+    // center strips.  Go back through and calculate the vertices on
+    // either side.
+    
+    PTA_Vertexf verts;
+    PTA_TexCoordf uvs;
+    PTA_Colorf colors;
+    
+    compute_billboard_vertices(verts, uvs, colors, camera_vec, 
+                               curve_segments, result);
+    
+    // Finally, build the lengths array to make them into proper
+    // triangle strips.  We don't need a vindex array here, since the
+    // vertices just happened to end up in tristrip order.
+    
+    PTA_int lengths;
+    int num_prims = 0;
+    
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      lengths.push_back(segment.size() * 2);
+      num_prims++;
+    }
+    
+    // And create a Geom for the rendering.
+    
+    PT(Geom) geom = new GeomTristrip;
+    geom->set_num_prims(num_prims);
+    geom->set_coords(verts);
+    if (get_uv_mode() != UV_none) {
+      geom->set_texcoords(uvs, G_PER_VERTEX);
+    }
+    if (get_use_vertex_color()) {
+      geom->set_colors(colors, G_PER_VERTEX);
+    } else {
+      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, trav);
   }
-  geom->set_lengths(lengths);
-  
-  CullableObject *object = new CullableObject(geom, data._state,
-                                              data._render_transform);
-  trav->get_cull_handler()->record_object(object, trav);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -501,63 +621,101 @@ render_tube(CullTraverser *trav, CullTraverserData &data,
   int num_slices = get_num_slices();
   int num_verts_per_slice;
 
-  PTA_Vertexf verts;
-  PTA_Normalf normals;
-  PTA_TexCoordf uvs;
-  PTA_Colorf colors;
-
-  compute_tube_vertices(verts, normals, uvs, colors,
-                        num_verts_per_slice, curve_segments, result);
-
-  // Finally, go back one more time and build up the vindex array, to
-  // tie all the triangle strips together.
-
-  PTA_ushort vindex;
-  PTA_int lengths;
+  if (use_qpgeom) {
+    PT(qpGeomVertexData) vdata = new qpGeomVertexData
+      ("rope", get_format(true), qpGeomUsageHint::UH_stream);
 
-  int num_prims = 0;
-  int vi = 0;
-  CurveSegments::const_iterator si;
-  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
-    const CurveSegment &segment = (*si);
-
-    for (int s = 0; s < num_slices; ++s) {
-      int s1 = (s + 1) % num_verts_per_slice;
-
-      for (size_t j = 0; j < segment.size(); ++j) {
-        vindex.push_back((vi + j) * num_verts_per_slice + s);
-        vindex.push_back((vi + j) * num_verts_per_slice + s1);
+    compute_tube_vertices(vdata,
+                          num_verts_per_slice, curve_segments, result);
+    
+    PT(qpGeomTristrips) strip = new qpGeomTristrips(qpGeomUsageHint::UH_stream);
+    // Finally, go through build up the index array, to tie all the
+    // triangle strips together.
+    int vi = 0;
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      for (int s = 0; s < num_slices; ++s) {
+        int s1 = (s + 1) % num_verts_per_slice;
+        
+        for (size_t j = 0; j < segment.size(); ++j) {
+          strip->add_vertex((vi + j) * num_verts_per_slice + s);
+          strip->add_vertex((vi + j) * num_verts_per_slice + s1);
+        }
+        
+        strip->close_primitive();
       }
-
-      lengths.push_back(segment.size() * 2);
-      num_prims++;
+      vi += (int)segment.size();
     }
-    vi += (int)segment.size();
-  }
 
-  // And create a Geom for the rendering.
-  
-  PT(Geom) geom = new GeomTristrip;
-  geom->set_num_prims(num_prims);
-  geom->set_coords(verts, vindex);
-  if (get_uv_mode() != UV_none) {
-    geom->set_texcoords(uvs, G_PER_VERTEX, vindex);
-  }
+    PT(qpGeom) geom = new qpGeom;
+    geom->set_vertex_data(vdata);
+    geom->add_primitive(strip);
 
-  if (get_normal_mode() == NM_vertex) {
-    geom->set_normals(normals, G_PER_VERTEX, vindex);
-  }
+    CullableObject *object = new CullableObject(geom, data._state,
+                                                data._render_transform);
+    trav->get_cull_handler()->record_object(object, trav);
 
-  if (get_use_vertex_color()) {
-    geom->set_colors(colors, G_PER_VERTEX, vindex);
   } else {
-    geom->set_colors(colors, G_OVERALL);
+    PTA_Vertexf verts;
+    PTA_Normalf normals;
+    PTA_TexCoordf uvs;
+    PTA_Colorf colors;
+    
+    compute_tube_vertices(verts, normals, uvs, colors,
+                          num_verts_per_slice, curve_segments, result);
+    
+    // Finally, go back one more time and build up the vindex array, to
+    // tie all the triangle strips together.
+    
+    PTA_ushort vindex;
+    PTA_int lengths;
+    
+    int num_prims = 0;
+    int vi = 0;
+    CurveSegments::const_iterator si;
+    for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+      const CurveSegment &segment = (*si);
+      
+      for (int s = 0; s < num_slices; ++s) {
+        int s1 = (s + 1) % num_verts_per_slice;
+        
+        for (size_t j = 0; j < segment.size(); ++j) {
+          vindex.push_back((vi + j) * num_verts_per_slice + s);
+          vindex.push_back((vi + j) * num_verts_per_slice + s1);
+        }
+        
+        lengths.push_back(segment.size() * 2);
+        num_prims++;
+      }
+      vi += (int)segment.size();
+    }
+    
+    // And create a Geom for the rendering.
+    
+    PT(Geom) geom = new GeomTristrip;
+    geom->set_num_prims(num_prims);
+    geom->set_coords(verts, vindex);
+    if (get_uv_mode() != UV_none) {
+      geom->set_texcoords(uvs, G_PER_VERTEX, vindex);
+    }
+    
+    if (get_normal_mode() == NM_vertex) {
+      geom->set_normals(normals, G_PER_VERTEX, vindex);
+    }
+    
+    if (get_use_vertex_color()) {
+      geom->set_colors(colors, G_PER_VERTEX, vindex);
+    } else {
+      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, trav);
   }
-  geom->set_lengths(lengths);
-
-  CullableObject *object = new CullableObject(geom, data._state,
-                                              data._render_transform);
-  trav->get_cull_handler()->record_object(object, trav);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -623,6 +781,186 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RopeNode::compute_thread_vertices
+//       Access: Private
+//  Description: Calculates the vertices for a RM_thread render.  This
+//               just copies the vertices more-or-less directly into
+//               the array.
+////////////////////////////////////////////////////////////////////
+void RopeNode::
+compute_thread_vertices(qpGeomVertexData *vdata,
+                        const RopeNode::CurveSegments &curve_segments) const {
+  qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+  qpGeomVertexWriter color(vdata, InternalName::get_color());
+  qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+  UVMode uv_mode = get_uv_mode();
+  float uv_scale = get_uv_scale();
+  bool u_dominant = get_uv_direction();
+  bool use_vertex_color = get_use_vertex_color();
+
+  float dist = 0.0f;
+  CurveSegments::const_iterator si;
+  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+    const CurveSegment &segment = (*si);
+    for (size_t j = 0; j < segment.size(); ++j) {
+      vertex.add_data3f(segment[j]._p);
+
+      if (use_vertex_color) {
+        color.add_data4f(segment[j]._c);
+      }
+
+      float uv_t = compute_uv_t(dist, uv_mode, uv_scale, segment, j);
+
+      if (uv_mode != UV_none) {
+        if (u_dominant) {
+          texcoord.add_data2f(uv_t, 0.0f);
+        } else {
+          texcoord.add_data2f(0.0f, uv_t);
+        }
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RopeNode::compute_billboard_vertices
+//       Access: Private
+//  Description: Calculates the vertices for a RM_billboard render.  This
+//               puts a pair of vertices on either side of each
+//               computed point in curve_segments.
+////////////////////////////////////////////////////////////////////
+void RopeNode::
+compute_billboard_vertices(qpGeomVertexData *vdata,
+                           const LVector3f &camera_vec,
+                           const RopeNode::CurveSegments &curve_segments,
+                           NurbsCurveResult *result) const {
+  qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+  qpGeomVertexWriter color(vdata, InternalName::get_color());
+  qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+  float thickness = get_thickness();
+  float radius = thickness * 0.5f;
+  UVMode uv_mode = get_uv_mode();
+  float uv_scale = get_uv_scale();
+  bool u_dominant = get_uv_direction();
+  bool use_vertex_color = get_use_vertex_color();
+
+  float dist = 0.0f;
+  CurveSegments::const_iterator si;
+  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+    const CurveSegment &segment = (*si);
+    for (size_t j = 0; j < segment.size(); ++j) {
+      LVector3f tangent;
+      compute_tangent(tangent, segment, j, result);
+
+      LVector3f norm = cross(tangent, camera_vec);
+      norm.normalize();
+
+      vertex.add_data3f(segment[j]._p + norm * radius);
+      vertex.add_data3f(segment[j]._p - norm * radius);
+
+      if (use_vertex_color) {
+        color.add_data4f(segment[j]._c);
+        color.add_data4f(segment[j]._c);
+      }
+
+      float uv_t = compute_uv_t(dist, uv_mode, uv_scale, segment, j);
+
+      if (uv_mode != UV_none) {
+        if (u_dominant) {
+          texcoord.add_data2f(uv_t, 1.0f);
+          texcoord.add_data2f(uv_t, 0.0f);
+        } else {
+          texcoord.add_data2f(1.0f, uv_t);
+          texcoord.add_data2f(0.0f, uv_t);
+        }
+      }
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RopeNode::compute_tube_vertices
+//       Access: Private
+//  Description: Calculates the vertices for a RM_tube render.  This
+//               puts a ring of vertices around each computed point in
+//               curve_segments.
+////////////////////////////////////////////////////////////////////
+void RopeNode::
+compute_tube_vertices(qpGeomVertexData *vdata,
+                      int &num_verts_per_slice,
+                      const RopeNode::CurveSegments &curve_segments,
+                      NurbsCurveResult *result) const {
+  qpGeomVertexWriter vertex(vdata, InternalName::get_vertex());
+  qpGeomVertexWriter normal(vdata, InternalName::get_normal());
+  qpGeomVertexWriter color(vdata, InternalName::get_color());
+  qpGeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
+
+  int num_slices = get_num_slices();
+  num_verts_per_slice = num_slices;
+
+  float thickness = get_thickness();
+  float radius = thickness * 0.5f;
+  UVMode uv_mode = get_uv_mode();
+  float uv_scale = get_uv_scale();
+  bool u_dominant = get_uv_direction();
+  NormalMode normal_mode = get_normal_mode();
+  bool use_vertex_color = get_use_vertex_color();
+
+  // If we are generating UV's, we will need to duplicate the vertices
+  // along the seam so that the UV's go through the whole range of
+  // 0..1 instead of reflecting in the last polygon before the seam.
+  if (uv_mode != UV_none) {
+    ++num_verts_per_slice;
+  }
+
+  LVector3f up = get_tube_up();
+
+  float dist = 0.0f;
+  CurveSegments::const_iterator si;
+  for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
+    const CurveSegment &segment = (*si);
+    for (size_t j = 0; j < segment.size(); ++j) {
+      LVector3f tangent;
+      compute_tangent(tangent, segment, j, result);
+
+      LVector3f norm = cross(tangent, up);
+      norm.normalize();
+      up = cross(norm, tangent);
+
+      LMatrix3f rotate = LMatrix3f::rotate_mat(360.0f / (float)num_slices,
+                                               tangent);
+
+      float uv_t = compute_uv_t(dist, uv_mode, uv_scale, segment, j);
+
+      for (int s = 0; s < num_verts_per_slice; ++s) {
+        vertex.add_data3f(segment[j]._p + norm * radius);
+
+        if (normal_mode == NM_vertex) {
+          normal.add_data3f(norm);
+        }
+
+        if (use_vertex_color) {
+          color.add_data4f(segment[j]._c);
+        }
+
+        norm = norm * rotate;
+
+        if (uv_mode != UV_none) {
+          float uv_s = (float)s / (float)num_slices;
+          if (u_dominant) {
+            texcoord.add_data2f(uv_t, uv_s);
+          } else {
+            texcoord.add_data2f(uv_s, uv_t);
+          }
+        }
+      }
+    }
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::compute_thread_vertices
 //       Access: Private

+ 16 - 0
panda/src/parametrics/ropeNode.h

@@ -23,6 +23,9 @@
 #include "nurbsCurveEvaluator.h"
 #include "pandaNode.h"
 #include "pStatCollector.h"
+#include "qpgeomVertexFormat.h"
+
+class qpGeomVertexData;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : RopeNode
@@ -143,6 +146,8 @@ protected:
   virtual BoundingVolume *recompute_internal_bound();
 
 private:
+  CPT(qpGeomVertexFormat) get_format(bool support_normals) const;
+
   BoundingVolume *do_recompute_bound(const NodePath &rel_to);
   void render_thread(CullTraverser *trav, CullTraverserData &data, 
                      NurbsCurveResult *result) const;
@@ -165,6 +170,17 @@ private:
   void get_connected_segments(CurveSegments &curve_segments,
                               const NurbsCurveResult *result) const;
 
+  void compute_thread_vertices(qpGeomVertexData *vdata,
+                               const CurveSegments &curve_segments) const;
+  void compute_billboard_vertices(qpGeomVertexData *vdata,
+                                  const LVector3f &camera_vec,
+                                  const CurveSegments &curve_segments,
+                                  NurbsCurveResult *result) const;
+  void compute_tube_vertices(qpGeomVertexData *vdata,
+                             int &num_verts_per_slice,
+                             const CurveSegments &curve_segments,
+                             NurbsCurveResult *result) const;
+
   void compute_thread_vertices(PTA_Vertexf &verts, PTA_TexCoordf &uvs, 
                                PTA_Colorf &colors,
                                const CurveSegments &curve_segments) const;