David Rose пре 23 година
родитељ
комит
a39fe8b02f

+ 2 - 2
panda/src/parametrics/Sources.pp

@@ -16,7 +16,7 @@
     parametricCurveDrawer.h curveFitter.I curveFitter.h  \
     hermiteCurve.h nurbsCurve.h \
     nurbsCurveDrawer.I nurbsCurveDrawer.h \
-    nurbsCurveEvaluator.h \
+    nurbsCurveEvaluator.I nurbsCurveEvaluator.h \
     nurbsCurveInterface.I nurbsCurveInterface.h \
     nurbsCurveResult.I nurbsCurveResult.h \
     nurbsMatrixVector.I nurbsMatrixVector.h \
@@ -50,7 +50,7 @@
     hermiteCurve.h \
     nurbsCurve.h \
     nurbsCurveDrawer.I nurbsCurveDrawer.h \
-    nurbsCurveEvaluator.h \
+    nurbsCurveEvaluator.I nurbsCurveEvaluator.h \
     nurbsCurveInterface.I nurbsCurveInterface.h \
     nurbsCurveResult.I nurbsCurveResult.h \
     nurbsMatrixVector.I nurbsMatrixVector.h \

+ 140 - 0
panda/src/parametrics/nurbsCurveEvaluator.I

@@ -0,0 +1,140 @@
+// Filename: nurbsCurveEvaluator.I
+// Created by:  drose (05Dec02)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://www.panda3d.org/license.txt .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::set_order
+//       Access: Published
+//  Description: Sets the order of the curve.  This resets the knot
+//               vector to the default knot vector for the number of
+//               vertices.
+//
+//               The order must be 1, 2, 3, or 4, and the value is one
+//               more than the degree of the curve.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsCurveEvaluator::
+set_order(int order) {
+  _order = order;
+  _knots_dirty = true;
+  _basis_dirty = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::get_order
+//       Access: Published
+//  Description: Returns the order of the curve as set by a previous
+//               call to set_order().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsCurveEvaluator::
+get_order() const {
+  return _order;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::get_num_vertices
+//       Access: Published
+//  Description: Returns the number of control vertices in the curve.
+//               This is the number passed to the last call to
+//               reset().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsCurveEvaluator::
+get_num_vertices() const {
+  return (int)_vertices.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::set_vertex
+//       Access: Published
+//  Description: Sets the nth control vertex of the curve.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsCurveEvaluator::
+set_vertex(int i, const LVecBase4f &vertex) {
+  nassertv(i >= 0 && i < (int)_vertices.size());
+  _vertices[i].set_vertex(vertex);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::set_vertex
+//       Access: Published
+//  Description: Sets the nth control vertex of the curve.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsCurveEvaluator::
+set_vertex(int i, const LVecBase3f &vertex, float weight) {
+  nassertv(i >= 0 && i < (int)_vertices.size());
+  _vertices[i].set_vertex(LVecBase4f(vertex[0] * weight, vertex[1] * weight, vertex[2] * weight, weight));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::get_vertex
+//       Access: Published
+//  Description: Returns the nth control vertex of the curve, relative
+//               to its indicated coordinate space.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase4f &NurbsCurveEvaluator::
+get_vertex(int i) const {
+  nassertr(i >= 0 && i < (int)_vertices.size(), LVecBase4f::zero());
+  return _vertices[i].get_vertex();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::set_vertex_space
+//       Access: Published
+//  Description: Sets the coordinate space of the nth control vertex.
+//               If this is not specified, or is set to an empty
+//               NodePath, the nth control vertex is deemed to be in
+//               the coordinate space passed to evaluate().
+//
+//               This specifies the space as a fixed NodePath, which
+//               is always the same NodePath.  Also see setting the
+//               space as a path string, which can specify a different
+//               NodePath for different instances of the curve.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsCurveEvaluator::
+set_vertex_space(int i, const NodePath &space) {
+  nassertv(i >= 0 && i < (int)_vertices.size());
+  _vertices[i].set_space(space);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::set_vertex_space
+//       Access: Published
+//  Description: Sets the coordinate space of the nth control vertex.
+//               If this is not specified, or is set to an empty
+//               string, the nth control vertex is deemed to be in
+//               the coordinate space passed to evaluate().
+//
+//               This specifies the space as a string, which describes
+//               the path to find the node relative to the rel_to
+//               NodePath when the curve is evaluated.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsCurveEvaluator::
+set_vertex_space(int i, const string &space) {
+  nassertv(i >= 0 && i < (int)_vertices.size());
+  _vertices[i].set_space(space);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveEvaluator::get_num_knots
+//       Access: Published
+//  Description: Returns the number of knot values in the curve.  This
+//               is based on the number of vertices and the order.
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsCurveEvaluator::
+get_num_knots() const {
+  return (int)_vertices.size() + _order;
+}

+ 5 - 104
panda/src/parametrics/nurbsCurveEvaluator.cxx

@@ -39,34 +39,6 @@ NurbsCurveEvaluator::
 ~NurbsCurveEvaluator() {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::set_order
-//       Access: Published
-//  Description: Sets the order of the curve.  This resets the knot
-//               vector to the default knot vector for the number of
-//               vertices.
-//
-//               The order must be 1, 2, 3, or 4, and the value is one
-//               more than the degree of the curve.
-////////////////////////////////////////////////////////////////////
-void NurbsCurveEvaluator::
-set_order(int order) {
-  _order = order;
-  _knots_dirty = true;
-  _basis_dirty = true;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::get_order
-//       Access: Published
-//  Description: Returns the order of the curve as set by a previous
-//               call to set_order().
-////////////////////////////////////////////////////////////////////
-int NurbsCurveEvaluator::
-get_order() const {
-  return _order;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveEvaluator::reset
 //       Access: Published
@@ -88,90 +60,19 @@ reset(int num_vertices) {
   _basis_dirty = true;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::get_num_vertices
-//       Access: Published
-//  Description: Returns the number of control vertices in the curve.
-//               This is the number passed to the last call to
-//               reset().
-////////////////////////////////////////////////////////////////////
-int NurbsCurveEvaluator::
-get_num_vertices() const {
-  return (int)_vertices.size();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::set_vertex
-//       Access: Published
-//  Description: Sets the nth control vertex of the curve.
-////////////////////////////////////////////////////////////////////
-void NurbsCurveEvaluator::
-set_vertex(int i, const LVecBase4f &vertex) {
-  nassertv(i >= 0 && i < (int)_vertices.size());
-  _vertices[i].set_vertex(vertex);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::set_vertex
-//       Access: Published
-//  Description: Sets the nth control vertex of the curve.
-////////////////////////////////////////////////////////////////////
-void NurbsCurveEvaluator::
-set_vertex(int i, const LVecBase3f &vertex, float weight) {
-  nassertv(i >= 0 && i < (int)_vertices.size());
-  _vertices[i].set_vertex(LVecBase4f(vertex[0] * weight, vertex[1] * weight, vertex[2] * weight, weight));
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::get_vertex
-//       Access: Published
-//  Description: Returns the nth control vertex of the curve, relative
-//               to its indicated coordinate space.
-////////////////////////////////////////////////////////////////////
-const LVecBase4f &NurbsCurveEvaluator::
-get_vertex(int i) const {
-  nassertr(i >= 0 && i < (int)_vertices.size(), LVecBase4f::zero());
-  return _vertices[i].get_vertex();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::set_vertex_space
-//       Access: Published
-//  Description: Sets the coordinate space of the nth control vertex.
-//               If this is not specified, or is set to an empty
-//               NodePath, the nth control vertex is deemed to be in
-//               the coordinate space passed to evaluate().
-////////////////////////////////////////////////////////////////////
-void NurbsCurveEvaluator::
-set_vertex_space(int i, const NodePath &space) {
-  nassertv(i >= 0 && i < (int)_vertices.size());
-  _vertices[i].set_space(space);
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveEvaluator::get_vertex_space
 //       Access: Published
 //  Description: Returns the coordinate space of the nth control
 //               vertex of the curve, expressed as a NodePath.
 ////////////////////////////////////////////////////////////////////
-const NodePath &NurbsCurveEvaluator::
-get_vertex_space(int i) const {
+NodePath NurbsCurveEvaluator::
+get_vertex_space(int i, const NodePath &rel_to) const {
 #ifndef NDEBUG
   static NodePath empty_node_path;
   nassertr(i >= 0 && i < (int)_vertices.size(), empty_node_path);
 #endif
-  return _vertices[i].get_space();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: NurbsCurveEvaluator::get_num_knots
-//       Access: Published
-//  Description: Returns the number of knot values in the curve.  This
-//               is based on the number of vertices and the order.
-////////////////////////////////////////////////////////////////////
-int NurbsCurveEvaluator::
-get_num_knots() const {
-  return (int)_vertices.size() + _order;
+  return _vertices[i].get_space(rel_to);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -242,7 +143,7 @@ get_vertices(pvector<LVecBase4f> &verts, const NodePath &rel_to) const {
   verts.reserve(verts.size() + num_vertices);
   int vi;
   for (vi = 0; vi < num_vertices; vi++) {
-    const NodePath &space = _vertices[vi].get_space();
+    NodePath space = _vertices[vi].get_space(rel_to);
     const LVecBase4f &vertex = _vertices[vi].get_vertex();
     if (space.is_empty()) {
       verts.push_back(vertex);
@@ -267,7 +168,7 @@ get_vertices(pvector<LPoint3f> &verts, const NodePath &rel_to) const {
   verts.reserve(verts.size() + num_vertices);
   int vi;
   for (vi = 0; vi < num_vertices; vi++) {
-    const NodePath &space = _vertices[vi].get_space();
+    const NodePath &space = _vertices[vi].get_space(rel_to);
     LVecBase4f vertex = _vertices[vi].get_vertex();
     if (!space.is_empty()) {
       const LMatrix4f &mat = space.get_mat(rel_to);

+ 12 - 9
panda/src/parametrics/nurbsCurveEvaluator.h

@@ -50,20 +50,21 @@ PUBLISHED:
   NurbsCurveEvaluator();
   ~NurbsCurveEvaluator();
 
-  void set_order(int order);
-  int get_order() const;
+  INLINE void set_order(int order);
+  INLINE int get_order() const;
 
   void reset(int num_vertices);
 
-  int get_num_vertices() const;
-  void set_vertex(int i, const LVecBase4f &vertex);
-  void set_vertex(int i, const LVecBase3f &vertex, float weight = 1.0);
-  const LVecBase4f &get_vertex(int i) const;
+  INLINE int get_num_vertices() const;
+  INLINE void set_vertex(int i, const LVecBase4f &vertex);
+  INLINE void set_vertex(int i, const LVecBase3f &vertex, float weight = 1.0);
+  INLINE const LVecBase4f &get_vertex(int i) const;
 
-  void set_vertex_space(int i, const NodePath &space);
-  const NodePath &get_vertex_space(int i) const;
+  INLINE void set_vertex_space(int i, const NodePath &space);
+  INLINE void set_vertex_space(int i, const string &space);
+  NodePath get_vertex_space(int i, const NodePath &rel_to) const;
 
-  int get_num_knots() const;
+  INLINE int get_num_knots() const;
   void set_knot(int i, float knot);
   float get_knot(int i) const;
 
@@ -90,5 +91,7 @@ private:
   NurbsMatrixVector _basis;
 };
 
+#include "nurbsCurveEvaluator.I"
+
 #endif
 

+ 32 - 0
panda/src/parametrics/nurbsCurveResult.I

@@ -65,6 +65,25 @@ eval_point(float t, LVecBase3f &point) {
   return true;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveResult::eval_tangent
+//       Access: Published
+//  Description: Computes the tangent to the curve at the indicated
+//               point in parametric time.  This tangent vector will
+//               not necessarily be normalized, and could be zero.
+//               See also eval_point().
+////////////////////////////////////////////////////////////////////
+INLINE bool NurbsCurveResult::
+eval_tangent(float t, LVecBase3f &tangent) {
+  int segment = find_segment(t);
+  if (segment == -1) {
+    return false;
+  }
+
+  eval_segment_tangent(segment, _prod.scale_t(segment, t), tangent);
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveResult::get_num_segments
 //       Access: Public
@@ -77,3 +96,16 @@ INLINE int NurbsCurveResult::
 get_num_segments() const {
   return _prod.get_num_segments();
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveResult::get_segment_t
+//       Access: Public
+//  Description: Accepts a t value in the range [0, 1], and assumed to
+//               be relative to the indicated segment (as in
+//               eval_segment_point()), and returns the corresponding
+//               t value in the entire curve (as in eval_point()).
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsCurveResult::
+get_segment_t(int segment, float t) const {
+  return t * (_prod.get_to(segment) - _prod.get_from(segment)) + _prod.get_from(segment);
+}

+ 18 - 0
panda/src/parametrics/nurbsCurveResult.cxx

@@ -82,6 +82,24 @@ eval_segment_point(int segment, float t, LVecBase3f &point) const {
   point.set(r[0] / r[3], r[1] / r[3], r[2] / r[3]);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsCurveResult::eval_segment_tangent
+//       Access: Published
+//  Description: As eval_segment_point, but computes the tangent to
+//               the curve at the indicated point.  The tangent vector
+//               will not necessarily be normalized, and could be
+//               zero, particularly at the endpoints.
+////////////////////////////////////////////////////////////////////
+void NurbsCurveResult::
+eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const {
+  const LMatrix4f &mat = _prod.get_matrix(segment);
+
+  float t2 = t*t;
+  LVecBase4f tvec(t2, t, 1.0f, 0.0f);
+  LVecBase4f r = tvec * mat;
+  tangent.set(r[0], r[1], r[2]);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsCurveResult::find_segment
 //       Access: Private

+ 3 - 0
panda/src/parametrics/nurbsCurveResult.h

@@ -49,9 +49,12 @@ PUBLISHED:
   INLINE float get_end_t() const;
 
   INLINE bool eval_point(float t, LVecBase3f &point);
+  INLINE bool eval_tangent(float t, LVecBase3f &tangent);
   
   INLINE int get_num_segments() const;
   void eval_segment_point(int segment, float t, LVecBase3f &point) const;
+  void eval_segment_tangent(int segment, float t, LVecBase3f &tangent) const;
+  INLINE float get_segment_t(int segment, float t) const;
   
 private:
   int find_segment(float t);

+ 24 - 5
panda/src/parametrics/nurbsVertex.I

@@ -34,7 +34,8 @@ NurbsVertex() {
 INLINE NurbsVertex::
 NurbsVertex(const NurbsVertex &copy) :
   _vertex(copy._vertex),
-  _space(copy._space)
+  _space(copy._space),
+  _space_path(copy._space_path)
 {
 }
 
@@ -47,6 +48,7 @@ INLINE void NurbsVertex::
 operator = (const NurbsVertex &copy) {
   _vertex = copy._vertex;
   _space = copy._space;
+  _space_path = copy._space_path;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -81,11 +83,24 @@ get_vertex() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: NurbsVertex::set_space
 //       Access: Public
-//  Description:
+//  Description: Sets the space of this vertex as a fixed NodePath.
 ////////////////////////////////////////////////////////////////////
 INLINE void NurbsVertex::
 set_space(const NodePath &space) {
   _space = space;
+  _space_path = string();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsVertex::set_space
+//       Access: Public
+//  Description: Sets the space of this vertex as a relative path from
+//               the rel_to node.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsVertex::
+set_space(const string &space) {
+  _space = NodePath();
+  _space_path = space;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -93,7 +108,11 @@ set_space(const NodePath &space) {
 //       Access: Public
 //  Description:
 ////////////////////////////////////////////////////////////////////
-INLINE const NodePath &NurbsVertex::
-get_space() const {
-  return _space;
+INLINE NodePath NurbsVertex::
+get_space(const NodePath &rel_to) const {
+  if (_space_path.empty()) {
+    return _space;
+  } else {
+    return rel_to.find(_space_path);
+  }
 }

+ 3 - 1
panda/src/parametrics/nurbsVertex.h

@@ -48,11 +48,13 @@ public:
   INLINE const LVecBase4f &get_vertex() const;
 
   INLINE void set_space(const NodePath &space);
-  INLINE const NodePath &get_space() const;
+  INLINE void set_space(const string &space);
+  INLINE NodePath get_space(const NodePath &rel_to) const;
 
 private:
   LVecBase4f _vertex;
   NodePath _space;
+  string _space_path;
 };
 
 #include "nurbsVertex.I"

+ 109 - 1
panda/src/parametrics/ropeNode.I

@@ -25,7 +25,11 @@
 INLINE RopeNode::CData::
 CData() {
   _curve = new NurbsCurveEvaluator;
+  _render_mode = RopeNode::RM_thread;
+  _uv_mode = RopeNode::UV_none;
+  _uv_scale.set(1.0f, 1.0f);
   _num_segs = 10;
+  _thickness = 1.0f;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -35,7 +39,12 @@ CData() {
 ////////////////////////////////////////////////////////////////////
 INLINE RopeNode::CData::
 CData(const RopeNode::CData &copy) :
-  _curve(copy._curve)
+  _curve(copy._curve),
+  _render_mode(copy._render_mode),
+  _uv_mode(copy._uv_mode),
+  _uv_scale(copy._uv_scale),
+  _num_segs(copy._num_segs),
+  _thickness(copy._thickness)
 {
 }
 
@@ -62,6 +71,79 @@ get_curve() const {
   return cdata->_curve;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: set_render_mode
+//       Access: Public
+//  Description: Specifies the method used to render the rope.  The
+//               simplest is RM_thread, which just draws a one-pixel
+//               line segment.
+////////////////////////////////////////////////////////////////////
+INLINE void RopeNode::
+set_render_mode(RopeNode::RenderMode render_mode) {
+  CDWriter cdata(_cycler);
+  cdata->_render_mode = render_mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_render_mode
+//       Access: Public
+//  Description: Returns the method used to render the rope.  See
+//               set_render_mode().
+////////////////////////////////////////////////////////////////////
+INLINE RopeNode::RenderMode RopeNode::
+get_render_mode() const {
+  CDReader cdata(_cycler);
+  return cdata->_render_mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: set_uv_mode
+//       Access: Public
+//  Description: Specifies the algorithm to use to generate UV's for
+//               the rope.
+////////////////////////////////////////////////////////////////////
+INLINE void RopeNode::
+set_uv_mode(RopeNode::UVMode uv_mode) {
+  CDWriter cdata(_cycler);
+  cdata->_uv_mode = uv_mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_uv_mode
+//       Access: Public
+//  Description: Returns the algorithm to use to generate UV's for the
+//               rope.
+////////////////////////////////////////////////////////////////////
+INLINE RopeNode::UVMode RopeNode::
+get_uv_mode() const {
+  CDReader cdata(_cycler);
+  return cdata->_uv_mode;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: set_uv_scale
+//       Access: Public
+//  Description: Specifies an additional scaling factor to apply to
+//               generated UV's for the rope.
+////////////////////////////////////////////////////////////////////
+INLINE void RopeNode::
+set_uv_scale(const LVecBase2f &uv_scale) {
+  CDWriter cdata(_cycler);
+  cdata->_uv_scale = uv_scale;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_uv_scale
+//       Access: Public
+//  Description: Returns the scaling factor to apply to generated UV's
+//               for the rope.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase2f &RopeNode::
+get_uv_scale() const {
+  CDReader cdata(_cycler);
+  return cdata->_uv_scale;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: set_num_segs
 //       Access: Public
@@ -87,3 +169,29 @@ get_num_segs() const {
   CDReader cdata(_cycler);
   return cdata->_num_segs;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: set_thickness
+//       Access: Public
+//  Description: Specifies the thickness of the rope, in pixels or in
+//               spatial units, depending on the render mode.  See
+//               set_render_mode().
+////////////////////////////////////////////////////////////////////
+INLINE void RopeNode::
+set_thickness(float thickness) {
+  nassertv(thickness >= 0);
+  CDWriter cdata(_cycler);
+  cdata->_thickness = thickness;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: get_thickness
+//       Access: Public
+//  Description: Returns the thickness of the rope.  See
+//               set_thickness().
+////////////////////////////////////////////////////////////////////
+INLINE float RopeNode::
+get_thickness() const {
+  CDReader cdata(_cycler);
+  return cdata->_thickness;
+}

+ 198 - 25
panda/src/parametrics/ropeNode.cxx

@@ -22,6 +22,7 @@
 #include "cullableObject.h"
 #include "cullHandler.h"
 #include "geomLinestrip.h"
+#include "geomTristrip.h"
 #include "bamWriter.h"
 #include "bamReader.h"
 #include "datagram.h"
@@ -149,35 +150,21 @@ has_cull_callback() const {
 ////////////////////////////////////////////////////////////////////
 bool RopeNode::
 cull_callback(CullTraverser *trav, CullTraverserData &data) {
-  // Create a new linestrip on-the-fly to render the rope.
-  int num_verts = get_num_segs() + 1;
-  if (num_verts >= 2) {
-    PTA_Vertexf verts;
-    PTA_int lengths;
-
+  // Create some geometry on-the-fly to render the rope.
+  if (get_num_segs() > 0) {
     NurbsCurveEvaluator *curve = get_curve();
     PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path());
 
-    int num_segments = result->get_num_segments();
-    if (num_segments > 0) {
-      for (int segment = 0; segment < num_segments; segment++) {
-        for (int i = 0; i < num_verts; i++) {
-          float t = (float)i / (float)(num_verts - 1);
-          LPoint3f point;
-          result->eval_segment_point(segment, t, point);
-          verts.push_back(point);
-        }
-        lengths.push_back(num_verts);
+    if (result->get_num_segments() > 0) {
+      switch (get_render_mode()) {
+      case RM_thread:
+        render_thread(trav, data, result);
+        break;
+
+      case RM_billboard:
+        render_billboard(trav, data, result);
+        break;
       }
-      
-      PT(Geom) geom = new GeomLinestrip;
-      geom->set_num_prims(num_segments);
-      geom->set_coords(verts);
-      geom->set_lengths(lengths);
-      
-      CullableObject *object = new CullableObject(geom, data._state,
-                                                  data._render_transform);
-      trav->get_cull_handler()->record_object(object);
     }
   }
   
@@ -245,6 +232,192 @@ recompute_internal_bound() {
   return reset_bound(NodePath(this));
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: RopeNode::render_thread
+//       Access: Private
+//  Description: Draws the rope in RM_thread mode.  This uses a
+//               GeomLinestrip to draw the rope in the simplest
+//               possible method, generally resulting in a
+//               one-pixel-wide curve.
+//
+//               In this mode, the thickness parameter represents a
+//               thickness in pixels, and is passed to the linestrip.
+//               However, you should be aware the DirectX does not
+//               support line thickness.
+////////////////////////////////////////////////////////////////////
+void RopeNode::
+render_thread(CullTraverser *trav, CullTraverserData &data, 
+              NurbsCurveResult *result) {
+  PTA_Vertexf verts;
+  PTA_TexCoordf uvs;
+  PTA_int lengths;
+
+  int num_verts = get_num_segs() + 1;
+  int num_segments = result->get_num_segments();
+  for (int segment = 0; segment < num_segments; segment++) {
+    for (int i = 0; i < num_verts; i++) {
+      float t = (float)i / (float)(num_verts - 1);
+      LPoint3f point;
+      result->eval_segment_point(segment, t, point);
+      verts.push_back(point);
+      uvs.push_back(TexCoordf(result->get_segment_t(segment, t), 0.0f));
+    }
+    lengths.push_back(num_verts);
+  }
+  
+  PT(Geom) geom = new GeomLinestrip;
+  geom->set_num_prims(num_segments);
+  geom->set_coords(verts);
+  geom->set_lengths(lengths);
+  
+  CullableObject *object = new CullableObject(geom, data._state,
+                                              data._render_transform);
+  trav->get_cull_handler()->record_object(object);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: RopeNode::render_billboard
+//       Access: Private
+//  Description: Draws the rope in RM_billboard mode.  This draws a
+//               series of triangle strips oriented to be
+//               perpendicular to the camera plane.
+//
+//               In this mode, thickness is in spatial units, and
+//               determines the with of the triangle strips.
+////////////////////////////////////////////////////////////////////
+void RopeNode::
+render_billboard(CullTraverser *trav, CullTraverserData &data, 
+                 NurbsCurveResult *result) {
+  const TransformState *net_transform = data._net_transform;
+  const TransformState *camera_transform = trav->get_camera_transform();
+
+  CPT(TransformState) rel_transform =
+    net_transform->invert_compose(camera_transform);
+  LVector3f camera_vec = LVector3f::forward() * rel_transform->get_mat();
+
+  float thickness = get_thickness();
+  float radius = thickness * 0.5f;
+  UVMode uv_mode = get_uv_mode();
+  LVecBase2f uv_scale = get_uv_scale();
+
+  // We can't just build one tristrip per segment.  Instead, we should
+  // build one continuous tristrip for all connected segments, so we
+  // can stitch them together properly at the seams.
+
+  int num_verts = get_num_segs() + 1;
+  int num_segments = result->get_num_segments();
+
+  vector_Vertexf center_verts;
+  vector_int center_lengths;
+  vector_float center_t;
+
+  LPoint3f point;
+  int cur_length = 0;
+  for (int segment = 0; segment < num_segments; segment++) {
+    LPoint3f first_point;
+    result->eval_segment_point(segment, 0.0f, first_point);
+    if (cur_length == 0 || point != first_point) {
+      // If the first point of this segment is different from the last
+      // point of the previous segment, end the tristrip and store the
+      // point.
+      if (cur_length != 0) {
+        center_lengths.push_back(cur_length);
+      }
+      center_verts.push_back(first_point);
+      center_t.push_back(result->get_segment_t(segment, 0.0f));
+      cur_length = 1;
+    }
+
+    // Store all the remaining points in this segment.
+    for (int i = 1; i < num_verts; i++) {
+      float t = (float)i / (float)(num_verts - 1);
+      result->eval_segment_point(segment, t, point);
+      center_verts.push_back(point);
+      center_t.push_back(result->get_segment_t(segment, t));
+      cur_length++;
+    }
+  }
+  if (cur_length != 0) {
+    center_lengths.push_back(cur_length);
+  }
+
+  // Now we have stored one or more sequences of vertices down the
+  // center strips.  Go back and convert them into actual tristrips.
+
+  PTA_Vertexf verts;
+  PTA_TexCoordf uvs;
+  PTA_int lengths;
+
+  int vi = 0;
+  int num_prims = 0;
+  float dist = 0.0f;
+  for (int i = 0; i < (int)center_lengths.size(); i++) {
+    int length = center_lengths[i];
+    for (int j = 0; j < length; j++) {
+      const Vertexf &point = center_verts[vi + j];
+      float t = center_t[vi + j];
+      LVector3f tangent;
+      // Rather than evaluating the curve for the tangent, we derive
+      // it from the neighboring points.  This gives us better
+      // behavior at the endpoints, where the tangent might go to
+      // zero.
+      if (j == 0) {
+        tangent = center_verts[vi + j + 1] - point;
+      } else if (j == length - 1) {
+        tangent = point - center_verts[vi + j - 1];
+      } else {
+        tangent = center_verts[vi + j + 1] - center_verts[vi + j - 1];
+      }
+      LVector3f cross = normalize(tangent.cross(camera_vec));
+      cross *= radius;
+      verts.push_back(point + cross);
+      verts.push_back(point - cross);
+      switch (uv_mode) {
+      case UV_none:
+        break;
+
+      case UV_parametric:
+        uvs.push_back(TexCoordf(t * uv_scale[0], uv_scale[1]));
+        uvs.push_back(TexCoordf(t * uv_scale[0], 0.0f));
+        break;
+
+      case UV_distance:
+        if (j != 0) {
+          LVector3f vec = point - center_verts[vi + j - 1];
+          dist += vec.length();
+        }
+        uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
+        uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
+        break;
+
+      case UV_distance2:
+        if (j != 0) {
+          LVector3f vec = point - center_verts[vi + j - 1];
+          dist += vec.length_squared();
+        }
+        uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
+        uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
+        break;
+      }
+    }
+    vi += length;
+    lengths.push_back(length * 2);
+    num_prims++;
+  }
+  
+  PT(Geom) geom = new GeomTristrip;
+  geom->set_num_prims(num_prims);
+  geom->set_coords(verts);
+  if (uv_mode != UV_none) {
+    geom->set_texcoords(uvs, G_PER_VERTEX);
+  }
+  geom->set_lengths(lengths);
+  
+  CullableObject *object = new CullableObject(geom, data._state,
+                                              data._render_transform);
+  trav->get_cull_handler()->record_object(object);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: RopeNode::register_with_read_factory
 //       Access: Public, Static

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

@@ -53,17 +53,46 @@ public:
   virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
 
 PUBLISHED:
+  enum RenderMode {
+    RM_thread,
+    RM_billboard
+  };
+  enum UVMode {
+    UV_none,
+    UV_parametric,
+    UV_distance,
+    UV_distance2,
+  };
+
   INLINE void set_curve(NurbsCurveEvaluator *curve);
   INLINE NurbsCurveEvaluator *get_curve() const;
 
+  INLINE void set_render_mode(RenderMode render_mode);
+  INLINE RenderMode get_render_mode() const;
+
+  INLINE void set_uv_mode(UVMode uv_mode);
+  INLINE UVMode get_uv_mode() const;
+
+  INLINE void set_uv_scale(const LVecBase2f &uv_scale);
+  INLINE const LVecBase2f &get_uv_scale() const;
+
   INLINE void set_num_segs(int num_segs);
   INLINE int get_num_segs() const;
 
+  INLINE void set_thickness(float thickness);
+  INLINE float get_thickness() const;
+
   BoundingVolume *reset_bound(const NodePath &rel_to);
 
 protected:
   virtual BoundingVolume *recompute_internal_bound();
 
+private:
+  void render_thread(CullTraverser *trav, CullTraverserData &data, 
+                     NurbsCurveResult *result);
+  void render_billboard(CullTraverser *trav, CullTraverserData &data, 
+                        NurbsCurveResult *result);
+
 private:
   // This is the data that must be cycled between pipeline stages.
   class EXPCL_PANDA CData : public CycleData {
@@ -75,7 +104,11 @@ private:
     virtual void fillin(DatagramIterator &scan, BamReader *manager);
 
     PT(NurbsCurveEvaluator) _curve;
+    RenderMode _render_mode;
+    UVMode _uv_mode;
+    LVecBase2f _uv_scale;
     int _num_segs;
+    float _thickness;
   };
 
   PipelineCycler<CData> _cycler;