17117f1b4Smrg
27117f1b4Smrg/*
37117f1b4Smrg * Mesa 3-D graphics library
47117f1b4Smrg *
57117f1b4Smrg * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
67117f1b4Smrg *
77117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
87117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
97117f1b4Smrg * to deal in the Software without restriction, including without limitation
107117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
117117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
127117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
137117f1b4Smrg *
147117f1b4Smrg * The above copyright notice and this permission notice shall be included
157117f1b4Smrg * in all copies or substantial portions of the Software.
167117f1b4Smrg *
177117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
187117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
197117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
247117f1b4Smrg */
257117f1b4Smrg
267117f1b4Smrg
277117f1b4Smrg/*
287117f1b4Smrg * eval.c was written by
297117f1b4Smrg * Bernd Barsuhn (bdbarsuh@cip.informatik.uni-erlangen.de) and
307117f1b4Smrg * Volker Weiss (vrweiss@cip.informatik.uni-erlangen.de).
317117f1b4Smrg *
327117f1b4Smrg * My original implementation of evaluators was simplistic and didn't
337117f1b4Smrg * compute surface normal vectors properly.  Bernd and Volker applied
347117f1b4Smrg * used more sophisticated methods to get better results.
357117f1b4Smrg *
367117f1b4Smrg * Thanks guys!
377117f1b4Smrg */
387117f1b4Smrg
397117f1b4Smrg
40c1f859d4Smrg#include "main/glheader.h"
41c1f859d4Smrg#include "main/config.h"
427117f1b4Smrg#include "m_eval.h"
437117f1b4Smrg
447117f1b4Smrgstatic GLfloat inv_tab[MAX_EVAL_ORDER];
457117f1b4Smrg
467117f1b4Smrg
477117f1b4Smrg
487117f1b4Smrg/*
497117f1b4Smrg * Horner scheme for Bezier curves
507117f1b4Smrg *
517117f1b4Smrg * Bezier curves can be computed via a Horner scheme.
527117f1b4Smrg * Horner is numerically less stable than the de Casteljau
537117f1b4Smrg * algorithm, but it is faster. For curves of degree n
547117f1b4Smrg * the complexity of Horner is O(n) and de Casteljau is O(n^2).
557117f1b4Smrg * Since stability is not important for displaying curve
567117f1b4Smrg * points I decided to use the Horner scheme.
577117f1b4Smrg *
587117f1b4Smrg * A cubic Bezier curve with control points b0, b1, b2, b3 can be
597117f1b4Smrg * written as
607117f1b4Smrg *
617117f1b4Smrg *        (([3]        [3]     )     [3]       )     [3]
627117f1b4Smrg * c(t) = (([0]*s*b0 + [1]*t*b1)*s + [2]*t^2*b2)*s + [3]*t^2*b3
637117f1b4Smrg *
647117f1b4Smrg *                                           [n]
657117f1b4Smrg * where s=1-t and the binomial coefficients [i]. These can
667117f1b4Smrg * be computed iteratively using the identity:
677117f1b4Smrg *
687117f1b4Smrg * [n]               [n  ]             [n]
697117f1b4Smrg * [i] = (n-i+1)/i * [i-1]     and     [0] = 1
707117f1b4Smrg */
717117f1b4Smrg
727117f1b4Smrg
737117f1b4Smrgvoid
747117f1b4Smrg_math_horner_bezier_curve(const GLfloat * cp, GLfloat * out, GLfloat t,
757117f1b4Smrg			  GLuint dim, GLuint order)
767117f1b4Smrg{
777117f1b4Smrg   GLfloat s, powert, bincoeff;
787117f1b4Smrg   GLuint i, k;
797117f1b4Smrg
807117f1b4Smrg   if (order >= 2) {
817117f1b4Smrg      bincoeff = (GLfloat) (order - 1);
827117f1b4Smrg      s = 1.0F - t;
837117f1b4Smrg
847117f1b4Smrg      for (k = 0; k < dim; k++)
857117f1b4Smrg	 out[k] = s * cp[k] + bincoeff * t * cp[dim + k];
867117f1b4Smrg
877117f1b4Smrg      for (i = 2, cp += 2 * dim, powert = t * t; i < order;
887117f1b4Smrg	   i++, powert *= t, cp += dim) {
897117f1b4Smrg	 bincoeff *= (GLfloat) (order - i);
907117f1b4Smrg	 bincoeff *= inv_tab[i];
917117f1b4Smrg
927117f1b4Smrg	 for (k = 0; k < dim; k++)
937117f1b4Smrg	    out[k] = s * out[k] + bincoeff * powert * cp[k];
947117f1b4Smrg      }
957117f1b4Smrg   }
967117f1b4Smrg   else {			/* order=1 -> constant curve */
977117f1b4Smrg
987117f1b4Smrg      for (k = 0; k < dim; k++)
997117f1b4Smrg	 out[k] = cp[k];
1007117f1b4Smrg   }
1017117f1b4Smrg}
1027117f1b4Smrg
1037117f1b4Smrg/*
1047117f1b4Smrg * Tensor product Bezier surfaces
1057117f1b4Smrg *
1067117f1b4Smrg * Again the Horner scheme is used to compute a point on a
1077117f1b4Smrg * TP Bezier surface. First a control polygon for a curve
1087117f1b4Smrg * on the surface in one parameter direction is computed,
1097117f1b4Smrg * then the point on the curve for the other parameter
1107117f1b4Smrg * direction is evaluated.
1117117f1b4Smrg *
1127117f1b4Smrg * To store the curve control polygon additional storage
1137117f1b4Smrg * for max(uorder,vorder) points is needed in the
1147117f1b4Smrg * control net cn.
1157117f1b4Smrg */
1167117f1b4Smrg
1177117f1b4Smrgvoid
1187117f1b4Smrg_math_horner_bezier_surf(GLfloat * cn, GLfloat * out, GLfloat u, GLfloat v,
1197117f1b4Smrg			 GLuint dim, GLuint uorder, GLuint vorder)
1207117f1b4Smrg{
1217117f1b4Smrg   GLfloat *cp = cn + uorder * vorder * dim;
1227117f1b4Smrg   GLuint i, uinc = vorder * dim;
1237117f1b4Smrg
1247117f1b4Smrg   if (vorder > uorder) {
1257117f1b4Smrg      if (uorder >= 2) {
1267117f1b4Smrg	 GLfloat s, poweru, bincoeff;
1277117f1b4Smrg	 GLuint j, k;
1287117f1b4Smrg
1297117f1b4Smrg	 /* Compute the control polygon for the surface-curve in u-direction */
1307117f1b4Smrg	 for (j = 0; j < vorder; j++) {
1317117f1b4Smrg	    GLfloat *ucp = &cn[j * dim];
1327117f1b4Smrg
1337117f1b4Smrg	    /* Each control point is the point for parameter u on a */
1347117f1b4Smrg	    /* curve defined by the control polygons in u-direction */
1357117f1b4Smrg	    bincoeff = (GLfloat) (uorder - 1);
1367117f1b4Smrg	    s = 1.0F - u;
1377117f1b4Smrg
1387117f1b4Smrg	    for (k = 0; k < dim; k++)
1397117f1b4Smrg	       cp[j * dim + k] = s * ucp[k] + bincoeff * u * ucp[uinc + k];
1407117f1b4Smrg
1417117f1b4Smrg	    for (i = 2, ucp += 2 * uinc, poweru = u * u; i < uorder;
1427117f1b4Smrg		 i++, poweru *= u, ucp += uinc) {
1437117f1b4Smrg	       bincoeff *= (GLfloat) (uorder - i);
1447117f1b4Smrg	       bincoeff *= inv_tab[i];
1457117f1b4Smrg
1467117f1b4Smrg	       for (k = 0; k < dim; k++)
1477117f1b4Smrg		  cp[j * dim + k] =
1487117f1b4Smrg		     s * cp[j * dim + k] + bincoeff * poweru * ucp[k];
1497117f1b4Smrg	    }
1507117f1b4Smrg	 }
1517117f1b4Smrg
1527117f1b4Smrg	 /* Evaluate curve point in v */
1537117f1b4Smrg	 _math_horner_bezier_curve(cp, out, v, dim, vorder);
1547117f1b4Smrg      }
1557117f1b4Smrg      else			/* uorder=1 -> cn defines a curve in v */
1567117f1b4Smrg	 _math_horner_bezier_curve(cn, out, v, dim, vorder);
1577117f1b4Smrg   }
1587117f1b4Smrg   else {			/* vorder <= uorder */
1597117f1b4Smrg
1607117f1b4Smrg      if (vorder > 1) {
1617117f1b4Smrg	 GLuint i;
1627117f1b4Smrg
1637117f1b4Smrg	 /* Compute the control polygon for the surface-curve in u-direction */
1647117f1b4Smrg	 for (i = 0; i < uorder; i++, cn += uinc) {
1657117f1b4Smrg	    /* For constant i all cn[i][j] (j=0..vorder) are located */
1667117f1b4Smrg	    /* on consecutive memory locations, so we can use        */
1677117f1b4Smrg	    /* horner_bezier_curve to compute the control points     */
1687117f1b4Smrg
1697117f1b4Smrg	    _math_horner_bezier_curve(cn, &cp[i * dim], v, dim, vorder);
1707117f1b4Smrg	 }
1717117f1b4Smrg
1727117f1b4Smrg	 /* Evaluate curve point in u */
1737117f1b4Smrg	 _math_horner_bezier_curve(cp, out, u, dim, uorder);
1747117f1b4Smrg      }
1757117f1b4Smrg      else			/* vorder=1 -> cn defines a curve in u */
1767117f1b4Smrg	 _math_horner_bezier_curve(cn, out, u, dim, uorder);
1777117f1b4Smrg   }
1787117f1b4Smrg}
1797117f1b4Smrg
1807117f1b4Smrg/*
1817117f1b4Smrg * The direct de Casteljau algorithm is used when a point on the
1827117f1b4Smrg * surface and the tangent directions spanning the tangent plane
1837117f1b4Smrg * should be computed (this is needed to compute normals to the
1847117f1b4Smrg * surface). In this case the de Casteljau algorithm approach is
1857117f1b4Smrg * nicer because a point and the partial derivatives can be computed
1867117f1b4Smrg * at the same time. To get the correct tangent length du and dv
1877117f1b4Smrg * must be multiplied with the (u2-u1)/uorder-1 and (v2-v1)/vorder-1.
1887117f1b4Smrg * Since only the directions are needed, this scaling step is omitted.
1897117f1b4Smrg *
1907117f1b4Smrg * De Casteljau needs additional storage for uorder*vorder
1917117f1b4Smrg * values in the control net cn.
1927117f1b4Smrg */
1937117f1b4Smrg
1947117f1b4Smrgvoid
1957117f1b4Smrg_math_de_casteljau_surf(GLfloat * cn, GLfloat * out, GLfloat * du,
1967117f1b4Smrg			GLfloat * dv, GLfloat u, GLfloat v, GLuint dim,
1977117f1b4Smrg			GLuint uorder, GLuint vorder)
1987117f1b4Smrg{
1997117f1b4Smrg   GLfloat *dcn = cn + uorder * vorder * dim;
2007117f1b4Smrg   GLfloat us = 1.0F - u, vs = 1.0F - v;
2017117f1b4Smrg   GLuint h, i, j, k;
2027117f1b4Smrg   GLuint minorder = uorder < vorder ? uorder : vorder;
2037117f1b4Smrg   GLuint uinc = vorder * dim;
2047117f1b4Smrg   GLuint dcuinc = vorder;
2057117f1b4Smrg
2067117f1b4Smrg   /* Each component is evaluated separately to save buffer space  */
2077117f1b4Smrg   /* This does not drasticaly decrease the performance of the     */
2087117f1b4Smrg   /* algorithm. If additional storage for (uorder-1)*(vorder-1)   */
2097117f1b4Smrg   /* points would be available, the components could be accessed  */
2107117f1b4Smrg   /* in the innermost loop which could lead to less cache misses. */
2117117f1b4Smrg
2127117f1b4Smrg#define CN(I,J,K) cn[(I)*uinc+(J)*dim+(K)]
2137117f1b4Smrg#define DCN(I, J) dcn[(I)*dcuinc+(J)]
2147117f1b4Smrg   if (minorder < 3) {
2157117f1b4Smrg      if (uorder == vorder) {
2167117f1b4Smrg	 for (k = 0; k < dim; k++) {
2177117f1b4Smrg	    /* Derivative direction in u */
2187117f1b4Smrg	    du[k] = vs * (CN(1, 0, k) - CN(0, 0, k)) +
2197117f1b4Smrg	       v * (CN(1, 1, k) - CN(0, 1, k));
2207117f1b4Smrg
2217117f1b4Smrg	    /* Derivative direction in v */
2227117f1b4Smrg	    dv[k] = us * (CN(0, 1, k) - CN(0, 0, k)) +
2237117f1b4Smrg	       u * (CN(1, 1, k) - CN(1, 0, k));
2247117f1b4Smrg
2257117f1b4Smrg	    /* bilinear de Casteljau step */
2267117f1b4Smrg	    out[k] = us * (vs * CN(0, 0, k) + v * CN(0, 1, k)) +
2277117f1b4Smrg	       u * (vs * CN(1, 0, k) + v * CN(1, 1, k));
2287117f1b4Smrg	 }
2297117f1b4Smrg      }
2307117f1b4Smrg      else if (minorder == uorder) {
2317117f1b4Smrg	 for (k = 0; k < dim; k++) {
2327117f1b4Smrg	    /* bilinear de Casteljau step */
2337117f1b4Smrg	    DCN(1, 0) = CN(1, 0, k) - CN(0, 0, k);
2347117f1b4Smrg	    DCN(0, 0) = us * CN(0, 0, k) + u * CN(1, 0, k);
2357117f1b4Smrg
2367117f1b4Smrg	    for (j = 0; j < vorder - 1; j++) {
2377117f1b4Smrg	       /* for the derivative in u */
2387117f1b4Smrg	       DCN(1, j + 1) = CN(1, j + 1, k) - CN(0, j + 1, k);
2397117f1b4Smrg	       DCN(1, j) = vs * DCN(1, j) + v * DCN(1, j + 1);
2407117f1b4Smrg
2417117f1b4Smrg	       /* for the `point' */
2427117f1b4Smrg	       DCN(0, j + 1) = us * CN(0, j + 1, k) + u * CN(1, j + 1, k);
2437117f1b4Smrg	       DCN(0, j) = vs * DCN(0, j) + v * DCN(0, j + 1);
2447117f1b4Smrg	    }
2457117f1b4Smrg
2467117f1b4Smrg	    /* remaining linear de Casteljau steps until the second last step */
2477117f1b4Smrg	    for (h = minorder; h < vorder - 1; h++)
2487117f1b4Smrg	       for (j = 0; j < vorder - h; j++) {
2497117f1b4Smrg		  /* for the derivative in u */
2507117f1b4Smrg		  DCN(1, j) = vs * DCN(1, j) + v * DCN(1, j + 1);
2517117f1b4Smrg
2527117f1b4Smrg		  /* for the `point' */
2537117f1b4Smrg		  DCN(0, j) = vs * DCN(0, j) + v * DCN(0, j + 1);
2547117f1b4Smrg	       }
2557117f1b4Smrg
2567117f1b4Smrg	    /* derivative direction in v */
2577117f1b4Smrg	    dv[k] = DCN(0, 1) - DCN(0, 0);
2587117f1b4Smrg
2597117f1b4Smrg	    /* derivative direction in u */
2607117f1b4Smrg	    du[k] = vs * DCN(1, 0) + v * DCN(1, 1);
2617117f1b4Smrg
2627117f1b4Smrg	    /* last linear de Casteljau step */
2637117f1b4Smrg	    out[k] = vs * DCN(0, 0) + v * DCN(0, 1);
2647117f1b4Smrg	 }
2657117f1b4Smrg      }
2667117f1b4Smrg      else {			/* minorder == vorder */
2677117f1b4Smrg
2687117f1b4Smrg	 for (k = 0; k < dim; k++) {
2697117f1b4Smrg	    /* bilinear de Casteljau step */
2707117f1b4Smrg	    DCN(0, 1) = CN(0, 1, k) - CN(0, 0, k);
2717117f1b4Smrg	    DCN(0, 0) = vs * CN(0, 0, k) + v * CN(0, 1, k);
2727117f1b4Smrg	    for (i = 0; i < uorder - 1; i++) {
2737117f1b4Smrg	       /* for the derivative in v */
2747117f1b4Smrg	       DCN(i + 1, 1) = CN(i + 1, 1, k) - CN(i + 1, 0, k);
2757117f1b4Smrg	       DCN(i, 1) = us * DCN(i, 1) + u * DCN(i + 1, 1);
2767117f1b4Smrg
2777117f1b4Smrg	       /* for the `point' */
2787117f1b4Smrg	       DCN(i + 1, 0) = vs * CN(i + 1, 0, k) + v * CN(i + 1, 1, k);
2797117f1b4Smrg	       DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
2807117f1b4Smrg	    }
2817117f1b4Smrg
2827117f1b4Smrg	    /* remaining linear de Casteljau steps until the second last step */
2837117f1b4Smrg	    for (h = minorder; h < uorder - 1; h++)
2847117f1b4Smrg	       for (i = 0; i < uorder - h; i++) {
2857117f1b4Smrg		  /* for the derivative in v */
2867117f1b4Smrg		  DCN(i, 1) = us * DCN(i, 1) + u * DCN(i + 1, 1);
2877117f1b4Smrg
2887117f1b4Smrg		  /* for the `point' */
2897117f1b4Smrg		  DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
2907117f1b4Smrg	       }
2917117f1b4Smrg
2927117f1b4Smrg	    /* derivative direction in u */
2937117f1b4Smrg	    du[k] = DCN(1, 0) - DCN(0, 0);
2947117f1b4Smrg
2957117f1b4Smrg	    /* derivative direction in v */
2967117f1b4Smrg	    dv[k] = us * DCN(0, 1) + u * DCN(1, 1);
2977117f1b4Smrg
2987117f1b4Smrg	    /* last linear de Casteljau step */
2997117f1b4Smrg	    out[k] = us * DCN(0, 0) + u * DCN(1, 0);
3007117f1b4Smrg	 }
3017117f1b4Smrg      }
3027117f1b4Smrg   }
3037117f1b4Smrg   else if (uorder == vorder) {
3047117f1b4Smrg      for (k = 0; k < dim; k++) {
3057117f1b4Smrg	 /* first bilinear de Casteljau step */
3067117f1b4Smrg	 for (i = 0; i < uorder - 1; i++) {
3077117f1b4Smrg	    DCN(i, 0) = us * CN(i, 0, k) + u * CN(i + 1, 0, k);
3087117f1b4Smrg	    for (j = 0; j < vorder - 1; j++) {
3097117f1b4Smrg	       DCN(i, j + 1) = us * CN(i, j + 1, k) + u * CN(i + 1, j + 1, k);
3107117f1b4Smrg	       DCN(i, j) = vs * DCN(i, j) + v * DCN(i, j + 1);
3117117f1b4Smrg	    }
3127117f1b4Smrg	 }
3137117f1b4Smrg
3147117f1b4Smrg	 /* remaining bilinear de Casteljau steps until the second last step */
3157117f1b4Smrg	 for (h = 2; h < minorder - 1; h++)
3167117f1b4Smrg	    for (i = 0; i < uorder - h; i++) {
3177117f1b4Smrg	       DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
3187117f1b4Smrg	       for (j = 0; j < vorder - h; j++) {
3197117f1b4Smrg		  DCN(i, j + 1) = us * DCN(i, j + 1) + u * DCN(i + 1, j + 1);
3207117f1b4Smrg		  DCN(i, j) = vs * DCN(i, j) + v * DCN(i, j + 1);
3217117f1b4Smrg	       }
3227117f1b4Smrg	    }
3237117f1b4Smrg
3247117f1b4Smrg	 /* derivative direction in u */
3257117f1b4Smrg	 du[k] = vs * (DCN(1, 0) - DCN(0, 0)) + v * (DCN(1, 1) - DCN(0, 1));
3267117f1b4Smrg
3277117f1b4Smrg	 /* derivative direction in v */
3287117f1b4Smrg	 dv[k] = us * (DCN(0, 1) - DCN(0, 0)) + u * (DCN(1, 1) - DCN(1, 0));
3297117f1b4Smrg
3307117f1b4Smrg	 /* last bilinear de Casteljau step */
3317117f1b4Smrg	 out[k] = us * (vs * DCN(0, 0) + v * DCN(0, 1)) +
3327117f1b4Smrg	    u * (vs * DCN(1, 0) + v * DCN(1, 1));
3337117f1b4Smrg      }
3347117f1b4Smrg   }
3357117f1b4Smrg   else if (minorder == uorder) {
3367117f1b4Smrg      for (k = 0; k < dim; k++) {
3377117f1b4Smrg	 /* first bilinear de Casteljau step */
3387117f1b4Smrg	 for (i = 0; i < uorder - 1; i++) {
3397117f1b4Smrg	    DCN(i, 0) = us * CN(i, 0, k) + u * CN(i + 1, 0, k);
3407117f1b4Smrg	    for (j = 0; j < vorder - 1; j++) {
3417117f1b4Smrg	       DCN(i, j + 1) = us * CN(i, j + 1, k) + u * CN(i + 1, j + 1, k);
3427117f1b4Smrg	       DCN(i, j) = vs * DCN(i, j) + v * DCN(i, j + 1);
3437117f1b4Smrg	    }
3447117f1b4Smrg	 }
3457117f1b4Smrg
3467117f1b4Smrg	 /* remaining bilinear de Casteljau steps until the second last step */
3477117f1b4Smrg	 for (h = 2; h < minorder - 1; h++)
3487117f1b4Smrg	    for (i = 0; i < uorder - h; i++) {
3497117f1b4Smrg	       DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
3507117f1b4Smrg	       for (j = 0; j < vorder - h; j++) {
3517117f1b4Smrg		  DCN(i, j + 1) = us * DCN(i, j + 1) + u * DCN(i + 1, j + 1);
3527117f1b4Smrg		  DCN(i, j) = vs * DCN(i, j) + v * DCN(i, j + 1);
3537117f1b4Smrg	       }
3547117f1b4Smrg	    }
3557117f1b4Smrg
3567117f1b4Smrg	 /* last bilinear de Casteljau step */
3577117f1b4Smrg	 DCN(2, 0) = DCN(1, 0) - DCN(0, 0);
3587117f1b4Smrg	 DCN(0, 0) = us * DCN(0, 0) + u * DCN(1, 0);
3597117f1b4Smrg	 for (j = 0; j < vorder - 1; j++) {
3607117f1b4Smrg	    /* for the derivative in u */
3617117f1b4Smrg	    DCN(2, j + 1) = DCN(1, j + 1) - DCN(0, j + 1);
3627117f1b4Smrg	    DCN(2, j) = vs * DCN(2, j) + v * DCN(2, j + 1);
3637117f1b4Smrg
3647117f1b4Smrg	    /* for the `point' */
3657117f1b4Smrg	    DCN(0, j + 1) = us * DCN(0, j + 1) + u * DCN(1, j + 1);
3667117f1b4Smrg	    DCN(0, j) = vs * DCN(0, j) + v * DCN(0, j + 1);
3677117f1b4Smrg	 }
3687117f1b4Smrg
3697117f1b4Smrg	 /* remaining linear de Casteljau steps until the second last step */
3707117f1b4Smrg	 for (h = minorder; h < vorder - 1; h++)
3717117f1b4Smrg	    for (j = 0; j < vorder - h; j++) {
3727117f1b4Smrg	       /* for the derivative in u */
3737117f1b4Smrg	       DCN(2, j) = vs * DCN(2, j) + v * DCN(2, j + 1);
3747117f1b4Smrg
3757117f1b4Smrg	       /* for the `point' */
3767117f1b4Smrg	       DCN(0, j) = vs * DCN(0, j) + v * DCN(0, j + 1);
3777117f1b4Smrg	    }
3787117f1b4Smrg
3797117f1b4Smrg	 /* derivative direction in v */
3807117f1b4Smrg	 dv[k] = DCN(0, 1) - DCN(0, 0);
3817117f1b4Smrg
3827117f1b4Smrg	 /* derivative direction in u */
3837117f1b4Smrg	 du[k] = vs * DCN(2, 0) + v * DCN(2, 1);
3847117f1b4Smrg
3857117f1b4Smrg	 /* last linear de Casteljau step */
3867117f1b4Smrg	 out[k] = vs * DCN(0, 0) + v * DCN(0, 1);
3877117f1b4Smrg      }
3887117f1b4Smrg   }
3897117f1b4Smrg   else {			/* minorder == vorder */
3907117f1b4Smrg
3917117f1b4Smrg      for (k = 0; k < dim; k++) {
3927117f1b4Smrg	 /* first bilinear de Casteljau step */
3937117f1b4Smrg	 for (i = 0; i < uorder - 1; i++) {
3947117f1b4Smrg	    DCN(i, 0) = us * CN(i, 0, k) + u * CN(i + 1, 0, k);
3957117f1b4Smrg	    for (j = 0; j < vorder - 1; j++) {
3967117f1b4Smrg	       DCN(i, j + 1) = us * CN(i, j + 1, k) + u * CN(i + 1, j + 1, k);
3977117f1b4Smrg	       DCN(i, j) = vs * DCN(i, j) + v * DCN(i, j + 1);
3987117f1b4Smrg	    }
3997117f1b4Smrg	 }
4007117f1b4Smrg
4017117f1b4Smrg	 /* remaining bilinear de Casteljau steps until the second last step */
4027117f1b4Smrg	 for (h = 2; h < minorder - 1; h++)
4037117f1b4Smrg	    for (i = 0; i < uorder - h; i++) {
4047117f1b4Smrg	       DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
4057117f1b4Smrg	       for (j = 0; j < vorder - h; j++) {
4067117f1b4Smrg		  DCN(i, j + 1) = us * DCN(i, j + 1) + u * DCN(i + 1, j + 1);
4077117f1b4Smrg		  DCN(i, j) = vs * DCN(i, j) + v * DCN(i, j + 1);
4087117f1b4Smrg	       }
4097117f1b4Smrg	    }
4107117f1b4Smrg
4117117f1b4Smrg	 /* last bilinear de Casteljau step */
4127117f1b4Smrg	 DCN(0, 2) = DCN(0, 1) - DCN(0, 0);
4137117f1b4Smrg	 DCN(0, 0) = vs * DCN(0, 0) + v * DCN(0, 1);
4147117f1b4Smrg	 for (i = 0; i < uorder - 1; i++) {
4157117f1b4Smrg	    /* for the derivative in v */
4167117f1b4Smrg	    DCN(i + 1, 2) = DCN(i + 1, 1) - DCN(i + 1, 0);
4177117f1b4Smrg	    DCN(i, 2) = us * DCN(i, 2) + u * DCN(i + 1, 2);
4187117f1b4Smrg
4197117f1b4Smrg	    /* for the `point' */
4207117f1b4Smrg	    DCN(i + 1, 0) = vs * DCN(i + 1, 0) + v * DCN(i + 1, 1);
4217117f1b4Smrg	    DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
4227117f1b4Smrg	 }
4237117f1b4Smrg
4247117f1b4Smrg	 /* remaining linear de Casteljau steps until the second last step */
4257117f1b4Smrg	 for (h = minorder; h < uorder - 1; h++)
4267117f1b4Smrg	    for (i = 0; i < uorder - h; i++) {
4277117f1b4Smrg	       /* for the derivative in v */
4287117f1b4Smrg	       DCN(i, 2) = us * DCN(i, 2) + u * DCN(i + 1, 2);
4297117f1b4Smrg
4307117f1b4Smrg	       /* for the `point' */
4317117f1b4Smrg	       DCN(i, 0) = us * DCN(i, 0) + u * DCN(i + 1, 0);
4327117f1b4Smrg	    }
4337117f1b4Smrg
4347117f1b4Smrg	 /* derivative direction in u */
4357117f1b4Smrg	 du[k] = DCN(1, 0) - DCN(0, 0);
4367117f1b4Smrg
4377117f1b4Smrg	 /* derivative direction in v */
4387117f1b4Smrg	 dv[k] = us * DCN(0, 2) + u * DCN(1, 2);
4397117f1b4Smrg
4407117f1b4Smrg	 /* last linear de Casteljau step */
4417117f1b4Smrg	 out[k] = us * DCN(0, 0) + u * DCN(1, 0);
4427117f1b4Smrg      }
4437117f1b4Smrg   }
4447117f1b4Smrg#undef DCN
4457117f1b4Smrg#undef CN
4467117f1b4Smrg}
4477117f1b4Smrg
4487117f1b4Smrg
4497117f1b4Smrg/*
4507117f1b4Smrg * Do one-time initialization for evaluators.
4517117f1b4Smrg */
4527117f1b4Smrgvoid
4537117f1b4Smrg_math_init_eval(void)
4547117f1b4Smrg{
4557117f1b4Smrg   GLuint i;
4567117f1b4Smrg
4577117f1b4Smrg   /* KW: precompute 1/x for useful x.
4587117f1b4Smrg    */
4597117f1b4Smrg   for (i = 1; i < MAX_EVAL_ORDER; i++)
4607117f1b4Smrg      inv_tab[i] = 1.0F / i;
4617117f1b4Smrg}
462