Home | History | Annotate | Line # | Download | only in interface
      1 /*
      2 ** License Applicability. Except to the extent portions of this file are
      3 ** made subject to an alternative license as permitted in the SGI Free
      4 ** Software License B, Version 1.1 (the "License"), the contents of this
      5 ** file are subject only to the provisions of the License. You may not use
      6 ** this file except in compliance with the License. You may obtain a copy
      7 ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
      8 ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
      9 **
     10 ** http://oss.sgi.com/projects/FreeB
     11 **
     12 ** Note that, as provided in the License, the Software is distributed on an
     13 ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
     14 ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
     15 ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
     16 ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
     17 **
     18 ** Original Code. The Original Code is: OpenGL Sample Implementation,
     19 ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
     20 ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
     21 ** Copyright in any portions created by third parties is as indicated
     22 ** elsewhere herein. All Rights Reserved.
     23 **
     24 ** Additional Notice Provisions: The application programming interfaces
     25 ** established by SGI in conjunction with the Original Code are The
     26 ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
     27 ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
     28 ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
     29 ** Window System(R) (Version 1.3), released October 19, 1998. This software
     30 ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
     31 ** published by SGI, but has not been independently verified as being
     32 ** compliant with the OpenGL(R) version 1.2.1 Specification.
     33 **
     34 */
     35 /*
     36 */
     37 
     38 #include <stdlib.h>
     39 #include <stdio.h>
     40 #include <assert.h>
     41 #include <math.h>
     42 #include "bezierEval.h"
     43 
     44 #ifdef __WATCOMC__
     45 #pragma warning 14  10
     46 #endif
     47 
     48 #define TOLERANCE 0.0001
     49 
     50 #ifndef MAX_ORDER
     51 #define MAX_ORDER 16
     52 #endif
     53 
     54 #ifndef MAX_DIMENSION
     55 #define MAX_DIMENSION 4
     56 #endif
     57 
     58 static void normalize(float vec[3]);
     59 static void crossProduct(float x[3], float y[3], float ret[3]);
     60 #if 0 // UNUSED
     61 static void bezierCurveEvalfast(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retpoint[]);
     62 #endif
     63 
     64 static float binomialCoefficients[8][8] = {
     65   {1,0,0,0,0,0,0,0},
     66   {1,1,0,0,0,0,0,0},
     67   {1,2,1,0,0,0,0,0},
     68   {1,3,3,1,0,0,0,0},
     69   {1,4,6,4,1,0,0,0},
     70   {1,5,10,10,5,1,0,0},
     71   {1,6,15,20,15,6,1,0},
     72   {1,7,21,35,35,21,7,1}
     73 };
     74 
     75 void bezierCurveEval(float u0, float u1, int order, float *ctlpoints, int stride, int dimension, float u, float retpoint[])
     76 {
     77   float uprime = (u-u0)/(u1-u0);
     78   float *ctlptr = ctlpoints;
     79   float oneMinusX = 1.0f-uprime;
     80   float XPower = 1.0f;
     81 
     82   int i,k;
     83   for(k=0; k<dimension; k++)
     84     retpoint[k] = (*(ctlptr + k));
     85 
     86   for(i=1; i<order; i++){
     87     ctlptr += stride;
     88     XPower *= uprime;
     89     for(k=0; k<dimension; k++) {
     90       retpoint[k] = retpoint[k]*oneMinusX + ctlptr[k]* binomialCoefficients[order-1][i] * XPower;
     91     }
     92   }
     93 }
     94 
     95 
     96 #if 0 // UNUSED
     97 /*order = degree +1 >=1.
     98  */
     99 void bezierCurveEvalfast(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retpoint[])
    100 {
    101   float uprime = (u-u0)/(u1-u0);
    102   float buf[MAX_ORDER][MAX_ORDER][MAX_DIMENSION];
    103   float* ctlptr = ctlpoints;
    104   int r, i,j;
    105   for(i=0; i<order; i++) {
    106     for(j=0; j<dimension; j++)
    107       buf[0][i][j] = ctlptr[j];
    108     ctlptr += stride;
    109   }
    110   for(r=1; r<order; r++){
    111     for(i=0; i<order-r; i++) {
    112       for(j=0; j<dimension; j++)
    113 	buf[r][i][j] = (1-uprime)*buf[r-1][i][j] + uprime*buf[r-1][i+1][j];
    114     }
    115   }
    116 
    117   for(j=0; j<dimension; j++)
    118     retpoint[j] = buf[order-1][0][j];
    119 }
    120 #endif
    121 
    122 
    123 /*order = degree +1 >=1.
    124  */
    125 void bezierCurveEvalDer(float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retDer[])
    126 {
    127   int i,k;
    128   float width = u1-u0;
    129   float *ctlptr = ctlpoints;
    130 
    131   float buf[MAX_ORDER][MAX_DIMENSION];
    132   if(order == 1){
    133     for(k=0; k<dimension; k++)
    134       retDer[k]=0;
    135   }
    136   for(i=0; i<order-1; i++){
    137     for(k=0; k<dimension; k++) {
    138       buf[i][k] = (ctlptr[stride+k] - ctlptr[k])*(order-1)/width;
    139     }
    140     ctlptr += stride;
    141   }
    142 
    143   bezierCurveEval(u0, u1, order-1, (float*) buf, MAX_DIMENSION,  dimension, u, retDer);
    144 }
    145 
    146 void bezierCurveEvalDerGen(int der, float u0, float u1, int order, float *ctlpoints, int stride,  int dimension, float u, float retDer[])
    147 {
    148   int i,k,r;
    149   float *ctlptr = ctlpoints;
    150   float width=u1-u0;
    151   float buf[MAX_ORDER][MAX_ORDER][MAX_DIMENSION];
    152   if(der<0) der=0;
    153   for(i=0; i<order; i++){
    154     for(k=0; k<dimension; k++){
    155       buf[0][i][k] = ctlptr[k];
    156     }
    157     ctlptr += stride;
    158   }
    159 
    160 
    161   for(r=1; r<=der; r++){
    162     for(i=0; i<order-r; i++){
    163       for(k=0; k<dimension; k++){
    164 	buf[r][i][k] = (buf[r-1][i+1][k] - buf[r-1][i][k])*(order-r)/width;
    165       }
    166     }
    167   }
    168 
    169   bezierCurveEval(u0, u1, order-der, (float *) (buf[der]), MAX_DIMENSION, dimension, u, retDer);
    170 }
    171 
    172 /*the Bezier bivarite polynomial is:
    173  * sum[i:0,uorder-1][j:0,vorder-1] { ctlpoints[i*ustride+j*vstride] * B(i)*B(j)
    174  * where B(i) and B(j) are basis functions
    175  */
    176 void bezierSurfEvalDerGen(int uder, int vder, float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float ret[])
    177 {
    178   int i;
    179   float newPoints[MAX_ORDER][MAX_DIMENSION];
    180 
    181   for(i=0; i<uorder; i++){
    182 
    183     bezierCurveEvalDerGen(vder, v0, v1, vorder, ctlpoints+ustride*i, vstride, dimension, v, newPoints[i]);
    184 
    185   }
    186 
    187   bezierCurveEvalDerGen(uder, u0, u1, uorder, (float *) newPoints, MAX_DIMENSION, dimension, u, ret);
    188 }
    189 
    190 
    191 /*division by w is performed*/
    192 void bezierSurfEval(float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float ret[])
    193 {
    194   bezierSurfEvalDerGen(0, 0, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, ret);
    195   if(dimension == 4) /*homogeneous*/{
    196     ret[0] /= ret[3];
    197     ret[1] /= ret[3];
    198     ret[2] /= ret[3];
    199   }
    200 }
    201 
    202 void bezierSurfEvalNormal(float u0, float u1, int uorder, float v0, float v1, int vorder, int dimension, float *ctlpoints, int ustride, int vstride, float u, float v, float retNormal[])
    203 {
    204   float partialU[4];
    205   float partialV[4];
    206   assert(dimension>=3 && dimension <=4);
    207   bezierSurfEvalDerGen(1,0, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, partialU);
    208   bezierSurfEvalDerGen(0,1, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, partialV);
    209 
    210   if(dimension == 3){/*inhomogeneous*/
    211     crossProduct(partialU, partialV, retNormal);
    212 
    213     normalize(retNormal);
    214 
    215     return;
    216   }
    217   else { /*homogeneous*/
    218     float val[4]; /*the point coordinates (without derivative)*/
    219     float newPartialU[MAX_DIMENSION];
    220     float newPartialV[MAX_DIMENSION];
    221     int i;
    222     bezierSurfEvalDerGen(0,0, u0, u1, uorder, v0, v1, vorder, dimension, ctlpoints, ustride, vstride, u, v, val);
    223 
    224     for(i=0; i<=2; i++){
    225       newPartialU[i] = partialU[i] * val[3] - val[i] * partialU[3];
    226       newPartialV[i] = partialV[i] * val[3] - val[i] * partialV[3];
    227     }
    228     crossProduct(newPartialU, newPartialV, retNormal);
    229     normalize(retNormal);
    230   }
    231 }
    232 
    233 /*if size is 0, then nothing is done*/
    234 static void normalize(float vec[3])
    235 {
    236   float size = (float)sqrt(vec[0]*vec[0] + vec[1]*vec[1] + vec[2]*vec[2]);
    237 
    238   if(size < TOLERANCE)
    239     {
    240 #ifdef DEBUG
    241       fprintf(stderr, "Warning: in oglBSpline.c normal is 0\n");
    242 #endif
    243       return;
    244     }
    245   else {
    246     vec[0] = vec[0]/size;
    247     vec[1] = vec[1]/size;
    248     vec[2] = vec[2]/size;
    249   }
    250 }
    251 
    252 
    253 static void crossProduct(float x[3], float y[3], float ret[3])
    254 {
    255   ret[0] = x[1]*y[2] - y[1]*x[2];
    256   ret[1] = x[2]*y[0] - y[2]*x[0];
    257   ret[2] = x[0]*y[1] - y[0]*x[1];
    258 
    259 }
    260 
    261