diff --git a/panda/src/parametrics/Sources.pp b/panda/src/parametrics/Sources.pp index e0125cb7b7..85d43e629a 100644 --- a/panda/src/parametrics/Sources.pp +++ b/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 \ diff --git a/panda/src/parametrics/nurbsCurveEvaluator.I b/panda/src/parametrics/nurbsCurveEvaluator.I new file mode 100644 index 0000000000..95a74f46d2 --- /dev/null +++ b/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 +// panda3d@yahoogroups.com . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// 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; +} diff --git a/panda/src/parametrics/nurbsCurveEvaluator.cxx b/panda/src/parametrics/nurbsCurveEvaluator.cxx index 8bb325a3c2..b8bfc8c79d 100644 --- a/panda/src/parametrics/nurbsCurveEvaluator.cxx +++ b/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 &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 &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); diff --git a/panda/src/parametrics/nurbsCurveEvaluator.h b/panda/src/parametrics/nurbsCurveEvaluator.h index 741f105931..c4e0bdbc4a 100644 --- a/panda/src/parametrics/nurbsCurveEvaluator.h +++ b/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 diff --git a/panda/src/parametrics/nurbsCurveResult.I b/panda/src/parametrics/nurbsCurveResult.I index 3f0c3eec7c..e2d6e62e44 100644 --- a/panda/src/parametrics/nurbsCurveResult.I +++ b/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); +} diff --git a/panda/src/parametrics/nurbsCurveResult.cxx b/panda/src/parametrics/nurbsCurveResult.cxx index 7150e6700f..72d8b179a4 100644 --- a/panda/src/parametrics/nurbsCurveResult.cxx +++ b/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 diff --git a/panda/src/parametrics/nurbsCurveResult.h b/panda/src/parametrics/nurbsCurveResult.h index 4864304d11..8fc4f6fb41 100644 --- a/panda/src/parametrics/nurbsCurveResult.h +++ b/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); diff --git a/panda/src/parametrics/nurbsVertex.I b/panda/src/parametrics/nurbsVertex.I index 53e876092c..7f7a3b9cb2 100644 --- a/panda/src/parametrics/nurbsVertex.I +++ b/panda/src/parametrics/nurbsVertex.I @@ -34,7 +34,8 @@ NurbsVertex() { INLINE NurbsVertex:: NurbsVertex(const NurbsVertex ©) : _vertex(copy._vertex), - _space(copy._space) + _space(copy._space), + _space_path(copy._space_path) { } @@ -47,6 +48,7 @@ INLINE void NurbsVertex:: operator = (const NurbsVertex ©) { _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); + } } diff --git a/panda/src/parametrics/nurbsVertex.h b/panda/src/parametrics/nurbsVertex.h index ad5d672186..45a414d6c2 100644 --- a/panda/src/parametrics/nurbsVertex.h +++ b/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" diff --git a/panda/src/parametrics/ropeNode.I b/panda/src/parametrics/ropeNode.I index 83925fb7d7..8f6c0d3ada 100644 --- a/panda/src/parametrics/ropeNode.I +++ b/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 ©) : - _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; +} diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index 3695fc7d70..d63d4d6cdd 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/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 diff --git a/panda/src/parametrics/ropeNode.h b/panda/src/parametrics/ropeNode.h index 372883affc..17e9b3c5bc 100644 --- a/panda/src/parametrics/ropeNode.h +++ b/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 _cycler;