Forráskód Böngészése

add NurbsSurfaceEvaluator

David Rose 22 éve
szülő
commit
a356726b35

+ 7 - 1
panda/src/parametrics/Sources.pp

@@ -20,6 +20,8 @@
     nurbsCurveInterface.I nurbsCurveInterface.h \
     nurbsCurveResult.I nurbsCurveResult.h \
     nurbsBasisVector.I nurbsBasisVector.h \
+    nurbsSurfaceEvaluator.I nurbsSurfaceEvaluator.h \
+    nurbsSurfaceResult.I nurbsSurfaceResult.h \
     nurbsVertex.h nurbsVertex.I \
     parametricCurve.h  \
     parametricCurveCollection.I parametricCurveCollection.h  \
@@ -33,9 +35,11 @@
     parametricCurveDrawer.cxx curveFitter.cxx hermiteCurve.cxx  \
     nurbsCurveDrawer.cxx \
     nurbsCurveEvaluator.cxx \
-    nurbsCurveResult.cxx \
     nurbsCurveInterface.cxx  \
+    nurbsCurveResult.cxx \
     nurbsBasisVector.cxx \
+    nurbsSurfaceEvaluator.cxx \
+    nurbsSurfaceResult.cxx \
     nurbsVertex.cxx \
     parametricCurve.cxx parametricCurveCollection.cxx  \
     piecewiseCurve.cxx \
@@ -54,6 +58,8 @@
     nurbsCurveInterface.I nurbsCurveInterface.h \
     nurbsCurveResult.I nurbsCurveResult.h \
     nurbsBasisVector.I nurbsBasisVector.h \
+    nurbsSurfaceEvaluator.I nurbsSurfaceEvaluator.h \
+    nurbsSurfaceResult.I nurbsSurfaceResult.h \
     nurbsVertex.h nurbsVertex.I \
     nurbsPPCurve.h \
     parametricCurve.h \

+ 2 - 1
panda/src/parametrics/nurbsCurveResult.cxx

@@ -40,7 +40,7 @@ NurbsCurveResult(const NurbsBasisVector &basis,
   _composed.reserve(num_segments);
   for (int i = 0; i < num_segments; i++) {
     int vi = _basis.get_vertex_index(i);
-    nassertv(vi >= 0 && vi < num_vertices);
+    nassertv(vi >= 0 && vi + order - 1 < num_vertices);
 
     // Create a geometry matrix from our (up to) four involved vertices.
     LMatrix4f geom;
@@ -86,6 +86,7 @@ eval_segment_point(int segment, float t, LVecBase3f &point) const {
   LVecBase4f tvec(t*t2, t2, t, 1.0f);
 
   float weight = tvec.dot(_composed[segment].get_col(3));
+
   point.set(tvec.dot(_composed[segment].get_col(0)) / weight,
             tvec.dot(_composed[segment].get_col(1)) / weight,
             tvec.dot(_composed[segment].get_col(2)) / weight);

+ 1 - 1
panda/src/parametrics/nurbsCurveResult.h

@@ -70,7 +70,7 @@ private:
 
   // We pre-compose the basis matrix and the geometry vectors, so we
   // have these handy for evaluation.  There is one entry in the
-  // _composed_vector for each entry in basis._segments.
+  // _composed for each entry in basis._segments.
   typedef pvector<LMatrix4f> ComposedGeom;
   ComposedGeom _composed;
 

+ 271 - 0
panda/src/parametrics/nurbsSurfaceEvaluator.I

@@ -0,0 +1,271 @@
+// Filename: nurbsSurfaceEvaluator.I
+// Created by:  drose (10Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: NurbsSurfaceEvaluator::set_u_order
+//       Access: Published
+//  Description: Sets the order of the surface in the U direction.
+//               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 surface.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsSurfaceEvaluator::
+set_u_order(int u_order) {
+  _u_order = u_order;
+  _u_knots_dirty = true;
+  _u_basis_dirty = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_u_order
+//       Access: Published
+//  Description: Returns the order of the surface in the U direction
+//               as set by a previous call to set_u_order().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceEvaluator::
+get_u_order() const {
+  return _u_order;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::set_v_order
+//       Access: Published
+//  Description: Sets the order of the surface in the V direction.
+//               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 surface.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsSurfaceEvaluator::
+set_v_order(int v_order) {
+  _v_order = v_order;
+  _v_knots_dirty = true;
+  _v_basis_dirty = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_v_order
+//       Access: Published
+//  Description: Returns the order of the surface in the V direction
+//               as set by a previous call to set_v_order().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceEvaluator::
+get_v_order() const {
+  return _v_order;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_num_u_vertices
+//       Access: Published
+//  Description: Returns the number of control vertices in the U
+//               direction on the surface.  This is the number passed
+//               to the last call to reset().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceEvaluator::
+get_num_u_vertices() const {
+  return _num_u_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_num_v_vertices
+//       Access: Published
+//  Description: Returns the number of control vertices in the V
+//               direction on the surface.  This is the number passed
+//               to the last call to reset().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceEvaluator::
+get_num_v_vertices() const {
+  return _num_v_vertices;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::set_vertex
+//       Access: Published
+//  Description: Sets the nth control vertex of the surface, as a vertex
+//               in 4-d homogeneous space.  In this form, the first
+//               three components of the vertex should already have
+//               been scaled by the fourth component, which is the
+//               homogeneous weight.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsSurfaceEvaluator::
+set_vertex(int ui, int vi, const LVecBase4f &vertex) {
+  nassertv(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices);
+  vert(ui, vi).set_vertex(vertex);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::set_vertex
+//       Access: Published
+//  Description: Sets the nth control vertex of the surface.  This
+//               flavor sets the vertex as a 3-d coordinate and a
+//               weight; the 3-d coordinate values are implicitly
+//               scaled up by the weight factor.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsSurfaceEvaluator::
+set_vertex(int ui, int vi, const LVecBase3f &vertex, float weight) {
+  nassertv(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices);
+  vert(ui, vi).set_vertex(LVecBase4f(vertex[0] * weight, vertex[1] * weight, vertex[2] * weight, weight));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_vertex
+//       Access: Published
+//  Description: Returns the nth control vertex of the surface, relative
+//               to its indicated coordinate space.
+////////////////////////////////////////////////////////////////////
+INLINE const LVecBase4f &NurbsSurfaceEvaluator::
+get_vertex(int ui, int vi) const {
+  nassertr(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices, LVecBase4f::zero());
+  return vert(ui, vi).get_vertex();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::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 surface.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsSurfaceEvaluator::
+set_vertex_space(int ui, int vi, const NodePath &space) {
+  nassertv(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices);
+  vert(ui, vi).set_space(space);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::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 surface is evaluated.
+////////////////////////////////////////////////////////////////////
+INLINE void NurbsSurfaceEvaluator::
+set_vertex_space(int ui, int vi, const string &space) {
+  nassertv(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices);
+  vert(ui, vi).set_space(space);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::set_extended_vertex
+//       Access: Public
+//  Description: Sets an n-dimensional vertex value.  This allows
+//               definition of a NURBS surface or surface in a sparse
+//               n-dimensional space, typically used for associating
+//               additional properties (like color or joint
+//               membership) with each vertex of a surface.
+//
+//               The value d is an arbitrary integer value and
+//               specifies the dimension of question for this
+//               particular vertex.  Any number of dimensions may be
+//               specified, and they need not be consecutive.  If a
+//               value for a given dimension is not specified, is it
+//               implicitly 0.0.
+//
+//               The value is implicitly scaled by the homogenous
+//               weight value--that is, the fourth component of the
+//               value passed to set_vertex().  This means the
+//               ordinary vertex must be set first, before the
+//               extended vertices can be set.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+set_extended_vertex(int ui, int vi, int d, float value) {
+  nassertv(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices);
+  vert(ui, vi).set_extended_vertex(d, value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::float_extended_vertex
+//       Access: Public
+//  Description: Returns an n-dimensional vertex value.  See
+//               set_extended_vertex().  This returns the value set
+//               for the indicated dimension, or 0.0 if nothing has
+//               been set.
+////////////////////////////////////////////////////////////////////
+float NurbsSurfaceEvaluator::
+get_extended_vertex(int ui, int vi, int d) const {
+  nassertr(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices, 0.0f);
+  return vert(ui, vi).get_extended_vertex(d);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_num_u_knots
+//       Access: Published
+//  Description: Returns the number of knot values in the surface in
+//               the U direction.  This is based on the number of
+//               vertices and the order.
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceEvaluator::
+get_num_u_knots() const {
+  return _num_u_vertices + _u_order;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_num_v_knots
+//       Access: Published
+//  Description: Returns the number of knot values in the surface in
+//               the V direction.  This is based on the number of
+//               vertices and the order.
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceEvaluator::
+get_num_v_knots() const {
+  return _num_v_vertices + _v_order;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::vert
+//       Access: Private
+//  Description: Internal accessor to dereference the 2-d vertex
+//               coordinate pair into a linear list of vertices.
+////////////////////////////////////////////////////////////////////
+INLINE NurbsVertex &NurbsSurfaceEvaluator::
+vert(int ui, int vi) {
+  return _vertices[ui * _num_v_vertices + vi];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::vert
+//       Access: Private
+//  Description: Internal accessor to dereference the 2-d vertex
+//               coordinate pair into a linear list of vertices.
+////////////////////////////////////////////////////////////////////
+INLINE const NurbsVertex &NurbsSurfaceEvaluator::
+vert(int ui, int vi) const {
+  return _vertices[ui * _num_v_vertices + vi];
+}

+ 353 - 0
panda/src/parametrics/nurbsSurfaceEvaluator.cxx

@@ -0,0 +1,353 @@
+// Filename: nurbsSurfaceEvaluator.cxx
+// Created by:  drose (10Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "nurbsSurfaceEvaluator.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::Constructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+NurbsSurfaceEvaluator::
+NurbsSurfaceEvaluator() {
+  _u_order = 4;
+  _v_order = 4;
+  _u_knots_dirty = true;
+  _v_knots_dirty = true;
+  _u_basis_dirty = true;
+  _v_basis_dirty = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+NurbsSurfaceEvaluator::
+~NurbsSurfaceEvaluator() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::reset
+//       Access: Published
+//  Description: Resets all the vertices and knots to their default
+//               values, and sets the surface up with the indicated
+//               number of vertices.  You must then call set_vertex()
+//               repeatedly to fill in all of the vertex values
+//               appropriately.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+reset(int num_u_vertices, int num_v_vertices) {
+  int num_vertices = num_u_vertices * num_v_vertices;
+  _vertices.clear();
+  _vertices.reserve(num_vertices);
+  _num_u_vertices = num_u_vertices;
+  _num_v_vertices = num_v_vertices;
+
+  for (int i = 0; i < num_vertices; i++) {
+    _vertices.push_back(NurbsVertex());
+  }
+  _u_knots_dirty = true;
+  _v_knots_dirty = true;
+  _u_basis_dirty = true;
+  _v_basis_dirty = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_vertex_space
+//       Access: Published
+//  Description: Returns the coordinate space of the nth control
+//               vertex of the surface, expressed as a NodePath.
+////////////////////////////////////////////////////////////////////
+NodePath NurbsSurfaceEvaluator::
+get_vertex_space(int ui, int vi, const NodePath &rel_to) const {
+#ifndef NDEBUG
+  static NodePath empty_node_path;
+  nassertr(ui >= 0 && ui < _num_u_vertices &&
+           vi >= 0 && vi < _num_v_vertices, empty_node_path);
+#endif
+  return vert(ui, vi).get_space(rel_to);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::set_u_knot
+//       Access: Published
+//  Description: Sets the value of the nth knot.  Each knot value
+//               should be greater than or equal to the preceding
+//               value.  If no knot values are set, a default knot
+//               vector is supplied.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+set_u_knot(int i, float knot) {
+  if (_u_knots_dirty) {
+    recompute_u_knots();
+  }
+  nassertv(i >= 0 && i < (int)_u_knots.size());
+  _u_knots[i] = knot;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_u_knot
+//       Access: Published
+//  Description: Returns the value of the nth knot.
+////////////////////////////////////////////////////////////////////
+float NurbsSurfaceEvaluator::
+get_u_knot(int i) const {
+  if (_u_knots_dirty) {
+    ((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
+  }
+  nassertr(i >= 0 && i < (int)_u_knots.size(), 0.0f);
+  return _u_knots[i];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::set_v_knot
+//       Access: Published
+//  Description: Sets the value of the nth knot.  Each knot value
+//               should be greater than or equal to the preceding
+//               value.  If no knot values are set, a default knot
+//               vector is supplied.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+set_v_knot(int i, float knot) {
+  if (_v_knots_dirty) {
+    recompute_v_knots();
+  }
+  nassertv(i >= 0 && i < (int)_v_knots.size());
+  _v_knots[i] = knot;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_v_knot
+//       Access: Published
+//  Description: Returns the value of the nth knot.
+////////////////////////////////////////////////////////////////////
+float NurbsSurfaceEvaluator::
+get_v_knot(int i) const {
+  if (_v_knots_dirty) {
+    ((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
+  }
+  nassertr(i >= 0 && i < (int)_v_knots.size(), 0.0f);
+  return _v_knots[i];
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::evaluate
+//       Access: Published
+//  Description: Returns a NurbsSurfaceResult object that represents the
+//               result of applying the knots to all of the current
+//               values of the vertices, transformed into the
+//               indicated coordinate space.
+////////////////////////////////////////////////////////////////////
+PT(NurbsSurfaceResult) NurbsSurfaceEvaluator::
+evaluate(const NodePath &rel_to) const {
+  if (_u_basis_dirty) {
+    ((NurbsSurfaceEvaluator *)this)->recompute_u_basis();
+  }
+  if (_v_basis_dirty) {
+    ((NurbsSurfaceEvaluator *)this)->recompute_v_basis();
+  }
+
+  // First, transform the vertices as appropriate.
+  pvector<LVecBase4f> vecs;
+  get_vertices(vecs, rel_to);
+
+  // And apply those transformed vertices to the basis matrices to
+  // derive the result.
+  return new NurbsSurfaceResult(_u_basis, _v_basis,
+                                &vecs[0], &_vertices[0],
+                                _num_u_vertices, _num_v_vertices);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_vertices
+//       Access: Public
+//  Description: Fills the indicated vector with the set of vertices
+//               in the surface, transformed to the given space.  This
+//               flavor returns the vertices in 4-dimensional
+//               homogenous space.
+//
+//               Vertices are arranged in linear sequence, with the v
+//               coordinate changing more rapidly.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+get_vertices(pvector<LVecBase4f> &verts, const NodePath &rel_to) const {
+  int num_vertices = (int)_vertices.size();
+  verts.reserve(verts.size() + num_vertices);
+  int vi;
+  for (vi = 0; vi < num_vertices; vi++) {
+    NodePath space = _vertices[vi].get_space(rel_to);
+    const LVecBase4f &vertex = _vertices[vi].get_vertex();
+    if (space.is_empty()) {
+      verts.push_back(vertex);
+    } else {
+      const LMatrix4f &mat = space.get_mat(rel_to);
+      verts.push_back(vertex * mat);
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::get_vertices
+//       Access: Public
+//  Description: Fills the indicated vector with the set of vertices
+//               in the surface, transformed to the given space.  This
+//               flavor returns the vertices in 4-dimensional
+//               homogenous space.
+//
+//               Vertices are arranged in linear sequence, with the v
+//               coordinate changing more rapidly.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+get_vertices(pvector<LPoint3f> &verts, const NodePath &rel_to) const {
+  int num_vertices = (int)_vertices.size();
+  verts.reserve(verts.size() + num_vertices);
+  int vi;
+  for (vi = 0; vi < num_vertices; vi++) {
+    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);
+      vertex = vertex * mat;
+    }
+    LPoint3f v3(vertex[0] / vertex[3], vertex[1] / vertex[3], vertex[2] / vertex[3]);
+    verts.push_back(v3);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::recompute_u_knots
+//       Access: Private
+//  Description: Creates a default knot vector.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+recompute_u_knots() {
+  _u_knots.clear();
+  int num_knots = get_num_u_knots();
+  _u_knots.reserve(num_knots);
+
+  float value = 0.0f;
+
+  int i = 0;
+  while (i < _u_order) {
+    _u_knots.push_back(value);
+    i++;
+  }
+  while (i < num_knots - _u_order) {
+    value += 1.0f;
+    _u_knots.push_back(value);
+    i++;
+  }
+  value += 1.0f;
+  while (i < num_knots) {
+    _u_knots.push_back(value);
+    i++;
+  }
+
+  _u_knots_dirty = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::recompute_v_knots
+//       Access: Private
+//  Description: Creates a default knot vector.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+recompute_v_knots() {
+  _v_knots.clear();
+  int num_knots = get_num_v_knots();
+  _v_knots.reserve(num_knots);
+
+  float value = 0.0f;
+
+  int i = 0;
+  while (i < _v_order) {
+    _v_knots.push_back(value);
+    i++;
+  }
+  while (i < num_knots - _v_order) {
+    value += 1.0f;
+    _v_knots.push_back(value);
+    i++;
+  }
+  value += 1.0f;
+  while (i < num_knots) {
+    _v_knots.push_back(value);
+    i++;
+  }
+
+  _v_knots_dirty = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::recompute_u_basis
+//       Access: Private
+//  Description: Recomputes the basis matrices according to the knot
+//               vector.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+recompute_u_basis() {
+  if (_u_knots_dirty) {
+    ((NurbsSurfaceEvaluator *)this)->recompute_u_knots();
+  }
+
+  _u_basis.clear(_u_order);
+  if (_num_u_vertices > _u_order - 1) {
+    int min_knot = _u_order;
+    int max_knot = _num_u_vertices + 1;
+    
+    for (int i = min_knot; i <= max_knot; i++) {
+      nassertv(i - 1 >= 0 && i < (int)_u_knots.size());
+      if (_u_knots[i - 1] < _u_knots[i]) {
+        // Here's a non-empty segment.
+        _u_basis.append_segment(i - _u_order, &_u_knots[i - _u_order]);
+      }
+    }
+  }
+
+  _u_basis_dirty = false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceEvaluator::recompute_v_basis
+//       Access: Private
+//  Description: Recomputes the basis matrices according to the knot
+//               vector.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceEvaluator::
+recompute_v_basis() {
+  if (_v_knots_dirty) {
+    ((NurbsSurfaceEvaluator *)this)->recompute_v_knots();
+  }
+
+  _v_basis.clear(_v_order);
+  if (_num_v_vertices > _v_order - 1) {
+    int min_knot = _v_order;
+    int max_knot = _num_v_vertices + 1;
+    
+    for (int i = min_knot; i <= max_knot; i++) {
+      nassertv(i - 1 >= 0 && i < (int)_v_knots.size());
+      if (_v_knots[i - 1] < _v_knots[i]) {
+        // Here's a non-empty segment.
+        _v_basis.append_segment(i - _v_order, &_v_knots[i - _v_order]);
+      }
+    }
+  }
+
+  _v_basis_dirty = false;
+}

+ 113 - 0
panda/src/parametrics/nurbsSurfaceEvaluator.h

@@ -0,0 +1,113 @@
+// Filename: nurbsSurfaceEvaluator.h
+// Created by:  drose (10Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef NURBSSURFACEEVALUATOR_H
+#define NURBSSURFACEEVALUATOR_H
+
+#include "pandabase.h"
+#include "nurbsBasisVector.h"
+#include "nurbsSurfaceResult.h"
+#include "nurbsVertex.h"
+#include "pointerTo.h"
+#include "vector_float.h"
+#include "pvector.h"
+#include "nodePath.h"
+#include "referenceCount.h"
+#include "luse.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : NurbsSurfaceEvaluator
+// Description : This class is an abstraction for evaluating NURBS
+//               surfaces.  It accepts an array of vertices, each of
+//               which may be in a different coordinate space (as
+//               defined by a NodePath), as well as an optional knot
+//               vector.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA NurbsSurfaceEvaluator : public ReferenceCount {
+PUBLISHED:
+  NurbsSurfaceEvaluator();
+  ~NurbsSurfaceEvaluator();
+
+  INLINE void set_u_order(int u_order);
+  INLINE int get_u_order() const;
+
+  INLINE void set_v_order(int v_order);
+  INLINE int get_v_order() const;
+
+  void reset(int num_u_vertices, int num_v_vertices);
+
+  INLINE int get_num_u_vertices() const;
+  INLINE int get_num_v_vertices() const;
+  INLINE void set_vertex(int ui, int vi, const LVecBase4f &vertex);
+  INLINE void set_vertex(int ui, int vi, const LVecBase3f &vertex, float weight = 1.0);
+  INLINE const LVecBase4f &get_vertex(int ui, int vi) const;
+
+  INLINE void set_vertex_space(int ui, int vi, const NodePath &space);
+  INLINE void set_vertex_space(int ui, int vi, const string &space);
+  NodePath get_vertex_space(int ui, int vi, const NodePath &rel_to) const;
+
+  INLINE void set_extended_vertex(int ui, int vi, int d, float value);
+  INLINE float get_extended_vertex(int ui, int vi, int d) const;
+
+  INLINE int get_num_u_knots() const;
+  void set_u_knot(int i, float knot);
+  float get_u_knot(int i) const;
+
+  INLINE int get_num_v_knots() const;
+  void set_v_knot(int i, float knot);
+  float get_v_knot(int i) const;
+
+  PT(NurbsSurfaceResult) evaluate(const NodePath &rel_to = NodePath()) const;
+
+public:
+  void get_vertices(pvector<LVecBase4f> &verts, const NodePath &rel_to) const;
+  void get_vertices(pvector<LPoint3f> &verts, const NodePath &rel_to) const;
+
+private:
+  INLINE NurbsVertex &vert(int ui, int vi);
+  INLINE const NurbsVertex &vert(int ui, int vi) const;
+
+  void recompute_u_knots();
+  void recompute_v_knots();
+  void recompute_u_basis();
+  void recompute_v_basis();
+
+  int _u_order;
+  int _v_order;
+
+  typedef pvector<NurbsVertex> Vertices;
+  Vertices _vertices;
+  int _num_u_vertices;
+  int _num_v_vertices;
+
+  bool _u_knots_dirty;
+  bool _v_knots_dirty;
+  typedef vector_float Knots;
+  Knots _u_knots;
+  Knots _v_knots;
+
+  bool _u_basis_dirty;
+  bool _v_basis_dirty;
+  NurbsBasisVector _u_basis;
+  NurbsBasisVector _v_basis;
+};
+
+#include "nurbsSurfaceEvaluator.I"
+
+#endif
+

+ 207 - 0
panda/src/parametrics/nurbsSurfaceResult.I

@@ -0,0 +1,207 @@
+// Filename: nurbsSurfaceResult.I
+// Created by:  drose (10Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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: NurbsSurfaceResult::Destructor
+//       Access: Published
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE NurbsSurfaceResult::
+~NurbsSurfaceResult() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_start_u
+//       Access: Public
+//  Description: Returns the first legal value of u on the surface.
+//               Usually this is 0.0.
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+get_start_u() const {
+  return _u_basis.get_start_t();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_end_u
+//       Access: Public
+//  Description: Returns the last legal value of u on the surface.
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+get_end_u() const {
+  return _u_basis.get_end_t();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_start_v
+//       Access: Public
+//  Description: Returns the first legal value of v on the surface.
+//               Usually this is 0.0.
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+get_start_v() const {
+  return _v_basis.get_start_t();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_end_v
+//       Access: Public
+//  Description: Returns the last legal value of v on the surface.
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+get_end_v() const {
+  return _v_basis.get_end_t();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::eval_point
+//       Access: Published
+//  Description: Computes the point on the surface corresponding to the
+//               indicated value in parametric time.  Returns true if
+//               the t value is value, false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool NurbsSurfaceResult::
+eval_point(float u, float v, LVecBase3f &point) {
+  int ui = find_u_segment(u);
+  int vi = find_v_segment(v);
+  if (ui == -1 || vi == -1) {
+    return false;
+  }
+
+  eval_segment_point(ui, vi, _u_basis.scale_t(ui, u), _v_basis.scale_t(vi, v),
+                     point);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::eval_normal
+//       Access: Published
+//  Description: Computes the normal to the surface at the indicated
+//               point in parametric time.  This normal vector will
+//               not necessarily be normalized, and could be zero.
+//               See also eval_point().
+////////////////////////////////////////////////////////////////////
+INLINE bool NurbsSurfaceResult::
+eval_normal(float u, float v, LVecBase3f &normal) {
+  int ui = find_u_segment(u);
+  int vi = find_v_segment(v);
+  if (ui == -1 || vi == -1) {
+    return false;
+  }
+
+  eval_segment_normal(ui, vi, _u_basis.scale_t(ui, u), _v_basis.scale_t(vi, v),
+                      normal);
+  return true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::eval_extended_point
+//       Access: Published
+//  Description: Evaluates the surface in n-dimensional space according
+//               to the extended vertices associated with the surface in
+//               the indicated dimension.
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+eval_extended_point(float u, float v, int d) {
+  int ui = find_u_segment(u);
+  int vi = find_v_segment(v);
+  if (ui == -1 || vi == -1) {
+    return 0.0f;
+  }
+
+  return eval_segment_extended_point(ui, vi, _u_basis.scale_t(ui, u), 
+                                     _v_basis.scale_t(vi, v), d);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_num_u_segments
+//       Access: Public
+//  Description: Returns the number of piecewise continuous segments
+//               within the surface in the U direction.  This number
+//               is usually not important unless you plan to call
+//               eval_segment_point().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceResult::
+get_num_u_segments() const {
+  return _u_basis.get_num_segments();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_num_v_segments
+//       Access: Public
+//  Description: Returns the number of piecewise continuous segments
+//               within the surface in the V direction.  This number
+//               is usually not important unless you plan to call
+//               eval_segment_point().
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceResult::
+get_num_v_segments() const {
+  return _v_basis.get_num_segments();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_segment_u
+//       Access: Public
+//  Description: Accepts a u value in the range [0, 1], and assumed to
+//               be relative to the indicated segment (as in
+//               eval_segment_point()), and returns the corresponding
+//               u value in the entire surface (as in eval_point()).
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+get_segment_u(int ui, float u) const {
+  return u * (_u_basis.get_to(ui) - _u_basis.get_from(ui)) + _u_basis.get_from(ui);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::get_segment_v
+//       Access: Public
+//  Description: Accepts a v value in the range [0, 1], and assumed to
+//               be relative to the indicated segment (as in
+//               eval_segment_point()), and returns the corresponding
+//               v value in the entire surface (as in eval_point()).
+////////////////////////////////////////////////////////////////////
+INLINE float NurbsSurfaceResult::
+get_segment_v(int vi, float v) const {
+  return v * (_v_basis.get_to(vi) - _v_basis.get_from(vi)) + _v_basis.get_from(vi);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::verti
+//       Access: Private
+//  Description: An internal function to dereference a 2-d vertex
+//               coordinate pair into a linear list of vertices.  This
+//               returns the linear index corresponding to the 2-d
+//               pair.
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceResult::
+verti(int ui, int vi) const {
+  return ui * _num_v_vertices + vi;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::segi
+//       Access: Private
+//  Description: An internal function to dereference a 2-d segment
+//               coordinate pair into a linear list of segments.  This
+//               returns the linear index corresponding to the 2-d
+//               pair.
+////////////////////////////////////////////////////////////////////
+INLINE int NurbsSurfaceResult::
+segi(int ui, int vi) const {
+  return ui * _v_basis.get_num_segments() + vi;
+}

+ 337 - 0
panda/src/parametrics/nurbsSurfaceResult.cxx

@@ -0,0 +1,337 @@
+// Filename: nurbsSurfaceResult.cxx
+// Created by:  drose (10Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "nurbsSurfaceResult.h"
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::Constructor
+//       Access: Public
+//  Description: The constructor automatically builds up the result as
+//               the product of the indicated set of basis matrices
+//               and the indicated table of control vertex positions.
+////////////////////////////////////////////////////////////////////
+NurbsSurfaceResult::
+NurbsSurfaceResult(const NurbsBasisVector &u_basis, 
+                   const NurbsBasisVector &v_basis, 
+                   const LVecBase4f vecs[], const NurbsVertex *verts,
+                   int num_u_vertices, int num_v_vertices) :
+  _u_basis(u_basis),
+  _v_basis(v_basis),
+  _verts(verts),
+  _num_u_vertices(num_u_vertices),
+  _num_v_vertices(num_v_vertices)
+{
+  _last_u_segment = -1;
+  _last_v_segment = -1;
+  int u_order = _u_basis.get_order();
+  int v_order = _v_basis.get_order();
+  int num_u_segments = _u_basis.get_num_segments();
+  int num_v_segments = _v_basis.get_num_segments();
+  int num_segments = num_u_segments * num_v_segments;
+
+  _composed.reserve(num_segments);
+  for (int ui = 0; ui < num_u_segments; ui++) {
+    const LMatrix4f &u_basis_mat = _u_basis.get_basis(ui);
+
+    int un = _u_basis.get_vertex_index(ui);
+    nassertv(un >= 0 && un + u_order - 1 < _num_u_vertices);
+
+    for (int vi = 0; vi < num_v_segments; vi++) {
+      LMatrix4f v_basis_transpose = transpose(_v_basis.get_basis(vi));
+
+      int vn = _v_basis.get_vertex_index(vi);
+      nassertv(vn >= 0 && vn + v_order - 1 < _num_v_vertices);
+
+      // Create four geometry matrices from our (up to) sixteen
+      // involved vertices.
+      LVecBase4f c[4][4];
+      for (int uni = 0; uni < 4; uni++) {
+        for (int vni = 0; vni < 4; vni++) {
+          c[uni][vni] = (uni < u_order && vni < v_order) ? 
+            vecs[verti(un + uni, vn + vni)] :
+            LVecBase4f::zero();
+        }
+      }
+
+      LMatrix4f geom_x(c[0][0][0], c[0][1][0], c[0][2][0], c[0][3][0],
+                       c[1][0][0], c[1][1][0], c[1][2][0], c[1][3][0],
+                       c[2][0][0], c[2][1][0], c[2][2][0], c[2][3][0],
+                       c[3][0][0], c[3][1][0], c[3][2][0], c[3][3][0]);
+
+      LMatrix4f geom_y(c[0][0][1], c[0][1][1], c[0][2][1], c[0][3][1],
+                       c[1][0][1], c[1][1][1], c[1][2][1], c[1][3][1],
+                       c[2][0][1], c[2][1][1], c[2][2][1], c[2][3][1],
+                       c[3][0][1], c[3][1][1], c[3][2][1], c[3][3][1]);
+
+      LMatrix4f geom_z(c[0][0][2], c[0][1][2], c[0][2][2], c[0][3][2],
+                       c[1][0][2], c[1][1][2], c[1][2][2], c[1][3][2],
+                       c[2][0][2], c[2][1][2], c[2][2][2], c[2][3][2],
+                       c[3][0][2], c[3][1][2], c[3][2][2], c[3][3][2]);
+      
+      LMatrix4f geom_w(c[0][0][3], c[0][1][3], c[0][2][3], c[0][3][3],
+                       c[1][0][3], c[1][1][3], c[1][2][3], c[1][3][3],
+                       c[2][0][3], c[2][1][3], c[2][2][3], c[2][3][3],
+                       c[3][0][3], c[3][1][3], c[3][2][3], c[3][3][3]);
+
+      // And compose these geometry matrices with the basis matrices
+      // to produce a new set of matrices, which will be used to
+      // evaluate the surface.
+      ComposedMats result;
+      result._x = u_basis_mat * geom_x * v_basis_transpose;
+      result._y = u_basis_mat * geom_y * v_basis_transpose;
+      result._z = u_basis_mat * geom_z * v_basis_transpose;
+      result._w = u_basis_mat * geom_w * v_basis_transpose;
+
+      _composed.push_back(result);
+    }
+  }
+
+  nassertv((int)_composed.size() == num_segments);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::eval_segment_point
+//       Access: Published
+//  Description: Evaluates the point on the surface corresponding to the
+//               indicated value in parametric time within the
+//               indicated surface segment.  u and v should be in the
+//               range [0, 1].
+//
+//               The surface is internally represented as a number of
+//               connected (or possibly unconnected) piecewise
+//               continuous segments.  The exact number of segments
+//               for a particular surface depends on the knot vector,
+//               and is returned by get_num_segments().  Normally,
+//               eval_point() is used to evaluate a point along the
+//               continuous surface, but when you care more about local
+//               continuity, you can use eval_segment_point() to
+//               evaluate the points along each segment.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceResult::
+eval_segment_point(int ui, int vi, float u, float v, LVecBase3f &point) const {
+  float u2 = u*u;
+  LVecBase4f uvec(u*u2, u2, u, 1.0f);
+  float v2 = v*v;
+  LVecBase4f vvec(v*v2, v2, v, 1.0f);
+  int i = segi(ui, vi);
+  nassertv(i >= 0 && i < (int)_composed.size());
+
+  float weight = vvec.dot(uvec * _composed[i]._w);
+
+  point.set(vvec.dot(uvec * _composed[i]._x) / weight,
+            vvec.dot(uvec * _composed[i]._y) / weight,
+            vvec.dot(uvec * _composed[i]._z) / weight);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::eval_segment_normal
+//       Access: Published
+//  Description: As eval_segment_point, but computes the normal to
+//               the surface at the indicated point.  The normal vector
+//               will not necessarily be normalized, and could be
+//               zero.
+////////////////////////////////////////////////////////////////////
+void NurbsSurfaceResult::
+eval_segment_normal(int ui, int vi, float u, float v, LVecBase3f &normal) const {
+  /*
+  float t2 = t*t;
+  LVecBase4f tvec(t2, t, 1.0f, 0.0f);
+
+  normal.set(tvec.dot(_composed[segment].get_col(0)),
+              tvec.dot(_composed[segment].get_col(1)),
+              tvec.dot(_composed[segment].get_col(2)));
+  */
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::eval_segment_extended_point
+//       Access: Published
+//  Description: Evaluates the surface in n-dimensional space according
+//               to the extended vertices associated with the surface in
+//               the indicated dimension.
+////////////////////////////////////////////////////////////////////
+float NurbsSurfaceResult::
+eval_segment_extended_point(int ui, int vi, float u, float v, int d) const {
+  /*
+  nassertr(segment >= 0 && segment < _basis.get_num_segments(), 0.0f);
+
+  int order = _basis.get_order();
+  int vi = _basis.get_vertex_index(segment);
+
+  LVecBase4f geom;
+  int ci = 0;
+  while (ci < order) {
+    geom[ci] = _verts[vi + ci].get_extended_vertex(d);
+    ci++;
+  }
+  while (ci < 4) {
+    geom[ci] = 0.0f;
+    ci++;
+  }
+
+  const LMatrix4f &basis = _basis.get_basis(segment);
+
+  // Compute matrix * column vector.
+  LVecBase4f composed_geom(basis.get_row(0).dot(geom),
+                           basis.get_row(1).dot(geom),
+                           basis.get_row(2).dot(geom),
+                           basis.get_row(3).dot(geom));
+
+  float t2 = t*t;
+  LVecBase4f tvec(t*t2, t2, t, 1.0f);
+
+  float weight = tvec.dot(_composed[segment].get_col(3));
+
+  float result = tvec.dot(composed_geom) / weight;
+  return result;
+  */
+  return 0.0f;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::find_u_segment
+//       Access: Private
+//  Description: Returns the index of the segment that contains the
+//               indicated value of t, or -1 if no segment contains
+//               this value.
+////////////////////////////////////////////////////////////////////
+int NurbsSurfaceResult::
+find_u_segment(float u) {
+  // Trivially check the endpoints of the surface.
+  if (u >= get_end_u()) {
+    return _u_basis.get_num_segments() - 1;
+  } else if (u <= get_start_u()) {
+    return 0;
+  }
+
+  // Check the last segment we searched for.  Often, two consecutive
+  // requests are for the same segment.
+  if (_last_u_segment != -1 && (u >= _last_u_from && u < _last_u_to)) {
+    return _last_u_segment;
+  }
+
+  // Look for the segment the hard way.
+  int segment = r_find_u_segment(u, 0, _u_basis.get_num_segments() - 1);
+  if (segment != -1) {
+    _last_u_segment = segment;
+    _last_u_from = _u_basis.get_from(segment);
+    _last_u_to = _u_basis.get_to(segment);
+  }
+  return segment;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::r_find_u_segment
+//       Access: Private
+//  Description: Recursively searches for the segment that contains
+//               the indicated value of t by performing a binary
+//               search.  This assumes the segments are stored in
+//               increasing order of t, and they don't overlap.
+////////////////////////////////////////////////////////////////////
+int NurbsSurfaceResult::
+r_find_u_segment(float u, int top, int bot) const {
+  if (bot < top) {
+    // Not found.
+    return -1;
+  }
+  int mid = (top + bot) / 2;
+  nassertr(mid >= 0 && mid < _u_basis.get_num_segments(), -1);
+
+  float from = _u_basis.get_from(mid);
+  float to = _u_basis.get_to(mid);
+  if (from > u) {
+    // Too high, try lower.
+    return r_find_u_segment(u, top, mid - 1);
+
+  } else if (to <= u) {
+    // Too low, try higher.
+    return r_find_u_segment(u, mid + 1, bot);
+
+  } else {
+    // Here we are!
+    return mid;
+  }
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::find_v_segment
+//       Access: Private
+//  Description: Returns the index of the segment that contains the
+//               indicated value of t, or -1 if no segment contains
+//               this value.
+////////////////////////////////////////////////////////////////////
+int NurbsSurfaceResult::
+find_v_segment(float v) {
+  // Trivially check the endpoints of the surface.
+  if (v >= get_end_v()) {
+    return _v_basis.get_num_segments() - 1;
+  } else if (v <= get_start_v()) {
+    return 0;
+  }
+
+  // Check the last segment we searched for.  Often, two consecutive
+  // requests are for the same segment.
+  if (_last_v_segment != -1 && (v >= _last_v_from && v < _last_v_to)) {
+    return _last_v_segment;
+  }
+
+  // Look for the segment the hard way.
+  int segment = r_find_v_segment(v, 0, _v_basis.get_num_segments() - 1);
+  if (segment != -1) {
+    _last_v_segment = segment;
+    _last_v_from = _v_basis.get_from(segment);
+    _last_v_to = _v_basis.get_to(segment);
+  }
+  return segment;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: NurbsSurfaceResult::r_find_v_segment
+//       Access: Private
+//  Description: Recursively searches for the segment that contains
+//               the indicated value of t by performing a binary
+//               search.  This assumes the segments are stored in
+//               increasing order of t, and they don't overlap.
+////////////////////////////////////////////////////////////////////
+int NurbsSurfaceResult::
+r_find_v_segment(float v, int top, int bot) const {
+  if (bot < top) {
+    // Not found.
+    return -1;
+  }
+  int mid = (top + bot) / 2;
+  nassertr(mid >= 0 && mid < _v_basis.get_num_segments(), -1);
+
+  float from = _v_basis.get_from(mid);
+  float to = _v_basis.get_to(mid);
+  if (from > v) {
+    // Too high, try lower.
+    return r_find_v_segment(v, top, mid - 1);
+
+  } else if (to <= v) {
+    // Too low, try higher.
+    return r_find_v_segment(v, mid + 1, bot);
+
+  } else {
+    // Here we are!
+    return mid;
+  }
+}
+

+ 101 - 0
panda/src/parametrics/nurbsSurfaceResult.h

@@ -0,0 +1,101 @@
+// Filename: nurbsSurfaceResult.h
+// Created by:  drose (10Oct03)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef NURBSSURFACERESULT_H
+#define NURBSSURFACERESULT_H
+
+#include "pandabase.h"
+#include "referenceCount.h"
+#include "nurbsBasisVector.h"
+
+class NurbsVertex;
+
+////////////////////////////////////////////////////////////////////
+//       Class : NurbsSurfaceResult
+// Description : The result of a NurbsSurfaceEvaluator.  This object
+//               represents a surface in a particular coordinate space.
+//               It can return the point and/or normal to the surface
+//               at any point.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA NurbsSurfaceResult : public ReferenceCount {
+public:
+  NurbsSurfaceResult(const NurbsBasisVector &u_basis, 
+                     const NurbsBasisVector &v_basis, 
+                     const LVecBase4f vecs[], const NurbsVertex *verts,
+                     int num_u_vertices, int num_v_vertices);
+
+PUBLISHED:
+  INLINE ~NurbsSurfaceResult();
+
+  INLINE float get_start_u() const;
+  INLINE float get_end_u() const;
+
+  INLINE float get_start_v() const;
+  INLINE float get_end_v() const;
+
+  INLINE bool eval_point(float u, float v, LVecBase3f &point);
+  INLINE bool eval_normal(float u, float v, LVecBase3f &normal);
+  INLINE float eval_extended_point(float u, float v, int d);
+  
+  INLINE int get_num_u_segments() const;
+  INLINE int get_num_v_segments() const;
+  void eval_segment_point(int ui, int vi, float u, float v, LVecBase3f &point) const;
+  void eval_segment_normal(int ui, int vi, float u, float v, LVecBase3f &normal) const;
+  float eval_segment_extended_point(int ui, int vi, float u, float v, int d) const;
+  INLINE float get_segment_u(int ui, float u) const;
+  INLINE float get_segment_v(int vi, float v) const;
+  
+private:
+  INLINE int verti(int ui, int vi) const;
+  INLINE int segi(int ui, int vi) const;
+
+  int find_u_segment(float u);
+  int r_find_u_segment(float u, int top, int bot) const;
+  int find_v_segment(float v);
+  int r_find_v_segment(float v, int top, int bot) const;
+
+  NurbsBasisVector _u_basis;
+  NurbsBasisVector _v_basis;
+  const NurbsVertex *_verts;
+  int _num_u_vertices;
+  int _num_v_vertices;
+
+  // We pre-compose the basis matrix and the geometry vectors, so we
+  // have these handy for evaluation.  There is one entry in the
+  // _composed for each entry in u_basis._segments *
+  // v_basis._segments.
+  class ComposedMats {
+  public:
+    LMatrix4f _x, _y, _z, _w;
+  };
+  typedef pvector<ComposedMats> ComposedGeom;
+  ComposedGeom _composed;
+
+
+  int _last_u_segment;
+  float _last_u_from;
+  float _last_u_to;
+  int _last_v_segment;
+  float _last_v_from;
+  float _last_v_to;
+};
+
+#include "nurbsSurfaceResult.I"
+
+#endif
+

+ 2 - 0
panda/src/parametrics/parametrics_composite2.cxx

@@ -5,6 +5,8 @@
 #include "parametricCurveDrawer.cxx"
 #include "nurbsCurveEvaluator.cxx"
 #include "nurbsCurveResult.cxx"
+#include "nurbsSurfaceEvaluator.cxx"
+#include "nurbsSurfaceResult.cxx"
 #include "nurbsBasisVector.cxx"
 #include "nurbsVertex.cxx"
 #include "ropeNode.cxx"