/*
Test GL-Curve-Functions
Test GL-Surface-Functions
  gluNurbsCurve gluNurbsSurface gluNurbsProperty
  glMap1f glMapGrid1d glMap2f glMapGrid2f


PROBLEMS gluNurbTess:
-) floats not doubles
-) does not give the index of the point of the boundary with VERTEX_DATA
     - cannot use indexed pointsets
-) macht 3Ecke die linear sind (ohne Fläche) eg on outerBound
-) wenn ein Punkt zu nah an der boundary, dann gibts eine senkrechte Fläche;
     dieser Punkt muess weg !
     TODO: test all faces along boundary,
      if their oppos.point is far enough from boundary-edge;
      if not: remove this point !


Nurb-Flaechen:
1)  kontrollpunkte (ctrlPoints)
2)  Knots f. u und v (Knots)
3)  Begrenzungskurven; da gibts 2 Varianten; eine uv- Kette oder eine
    echte Nurb-Curve. Bis jetz hab ich nur fuer u-v-Kette ein Beispiel:
    Alle Werte sind u und v-Werte zwischen 0 und 1.
    Muessen CCW sein (sonst Loch)
    Muessen geschlossen sein !!



Hier noch Vorschlag structs:



//  Randkurve / Bounding Curve.
typedef struct {int basTyp; void *basDat;
                int ptNr; double *ptDat,
                int knNr, double *knDat, v0, v1;}             CurvBound;
// basTyp   Typ Basiskurve (Line - Circ oder B_Spline; NULL: keine.
// basDat   Line, Circ oder B_Spline
// ptNr     Anzahl U-V-Werte
// ptDat    U-V-Werte
// knNr     Anzahl KnotValues oder 0
// knDat    KnotValues oder NULL
// v0       Startwert
// v1       Endwert



// BegrenzteFlaeche / Surface-Patch
typedef struct {int basTyp; void *basDat;
                int cvNr;  CurvBound *cvTab;}                  SurPatch;
// basTyp   Plane od Ruled Surf oder RevSur
// basDat   Plane ....
// cvNr     Anzahl Randkurven
// cvTab    Tabelle Randkurven (Randkontur)






*/


#ifdef _MSC_VER
#define GLU_CB static void CALLBACK
#else
#define GLU_CB static void
#endif


#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>



#include <GL/gl.h>
#include <GL/glu.h>



#include "../ut/ut_geo.h"                // Point-def


#define COL_RED    0
#define COL_YELLOW 1
#define COL_SUR    2

static GLfloat colTab [][4] = {
  1.0, 0.0, 0.0, 1.0,
  1.0, 1.0, 0.0, 1.0,
  0.6, 0.5, 0.5, 1.0};




GLU_CB GLCB_error (GLenum errNo);
GLU_CB GLCB_begin (GLenum type);
GLU_CB GLCB_vertex (GLfloat *vertex);
// GLU_CB GLCB_vert_dat (GLfloat *vertex, void *data);
GLU_CB GLCB_normal (GLfloat *normal);


#define PT_MAX 1000
static Point pa[PT_MAX];
static int ptNr, patchTyp;
#define TRI_MAX 300
static Triangle triTab[TRI_MAX];



/*
//================================================================
  GLU_CB GLCB_vert_dat (GLfloat *vertex, void *data) {
//================================================================
// - cannot test if a tesselated point (out in GLU_NURBS_VERTEX(_DATA))
//   belong to an outer or inner boundary (given by gluPwlCurve)
//   (returned data for all points identical)


   glVertex3fv(vertex);  //  resubmit rendering directive

   printf ("glVertex3f (%5.3f, %5.3f, %5.3f, %p)\n",
     vertex[0], vertex[1], vertex[2], data);
}
*/


//================================================================
  GLU_CB GLCB_vertex (GLfloat *vertex) {
//================================================================


   printf ("glVertex3f (%5.3f, %5.3f, %5.3f)\n",
     vertex[0], vertex[1], vertex[2]);

   // glVertex3fv(vertex);  //  resubmit rendering directive

  pa[ptNr].x = vertex[0];
  pa[ptNr].y = vertex[1];
  pa[ptNr].z = vertex[2];

  if(ptNr < PT_MAX) ++ptNr;
  else printf("********* ERROR GLCB_vertex EOF\n");

}


//================================================================
  GLU_CB GLCB_normal (GLfloat *normal) {
//================================================================
 
   // glNormal3fv(normal);  //  resubmit rendering directive

   printf ("glNormal3f (%5.3f, %5.3f, %5.3f)\n",
           normal[0], normal[1], normal[2]);
}


//================================================================
  GLU_CB GLCB_begin (GLenum type) {
//================================================================
 
   printf ("glBegin(");

   // glBegin (type);  //  resubmit rendering directive

  ptNr = 0;
  patchTyp = type;


   switch (type) {  /*  print diagnostic message  */
      case GL_LINES:
   printf ("GL_LINES)\n");
   break;
      case GL_LINE_LOOP:
   printf ("GL_LINE_LOOP)\n");
   break;
      case GL_LINE_STRIP:
   printf ("GL_LINE_STRIP)\n");
   break;
      case GL_TRIANGLES:
   printf ("GL_TRIANGLES)\n");
   break;
      case GL_TRIANGLE_STRIP:
   printf ("GL_TRIANGLE_STRIP)\n");
   break;
      case GL_TRIANGLE_FAN:
   printf ("GL_TRIANGLE_FAN)\n");
   break;
      case GL_QUADS:
   printf ("GL_QUADS)\n");
   break;
      case GL_QUAD_STRIP:
   printf ("GL_QUAD_STRIP)\n");
   break;
      case GL_POLYGON:
   printf ("GL_POLYGON)\n");
   break;
      default:
   break;
   }
}


//================================================================
  GLU_CB GLCB_end () {
//================================================================
 
   printf ("glEnd() ptNr=%d\n",ptNr);

   // glEnd();  /*  resubmit rendering directive  */

  // display as points
  // tst_gl1_point_d (pa, ptNr, (GLfloat*)&colTab[COL_YELLOW]);


  // display triangles
  tst_gl1_patch__ (pa, ptNr, patchTyp);


}


//=========================================================
  GLU_CB GLCB_error (GLenum errNo) {
//=========================================================

  const GLubyte *estring;

  printf("****** GLCB_error %d\n",errNo);

  estring = gluErrorString(errNo);
  fprintf (stderr, "Nurbs Error: %s\n", estring);
  // exit (0);


}


//=========================================================
  int gl_light1 () {
//=========================================================


  GLfloat light0_pos[4]   = { -50.0, 50.0, 0.0, 0.0 };
  GLfloat light0_color[4] = { .6, .6, .6, 1.0 }; // white light
  GLfloat light1_pos[4]   = {  50.0, 50.0, 0.0, 0.0 };
  GLfloat light1_color[4] = { .4, .4, 1, 1.0 };  // cold blue light

  // remove back faces
  glDisable(GL_CULL_FACE);
  glEnable(GL_DEPTH_TEST);

  // speedups
  // glEnable(GL_DITHER);
  // glShadeModel(GL_SMOOTH);
  // glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
  // glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);

  // light
  glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
  glLightfv(GL_LIGHT0, GL_DIFFUSE,  light0_color);
  glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);
  glLightfv(GL_LIGHT1, GL_DIFFUSE,  light1_color);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHT1);
  glEnable(GL_LIGHTING);

  // glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE);
  glEnable(GL_COLOR_MATERIAL);

}


//=========================================================
  int tst_gl1_nurbCrv () {
//=========================================================
// NurbsCurve


  int    i1;
  Point  pt1;

  // NURBS object pointer
  GLUnurbsObj *pNurb = NULL;



  // Mesh extends four units -6 to +6 along x and y axis
  // Lies in Z plane
  //                 u  v  (x,y,z)
  GLfloat ctrlPoints[4][3]  =
              {{  -6.0f, -6.0f, 0.0f},
               {   2.0f, -2.0f, 8.0f},
               {   2.0f,  6.0f, 0.0f},
               {   6.0f, 6.0f,  0.0f}};


  // Knot sequence for the NURB
  GLfloat Knots[8] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};



  // Setup the Nurbs object
  pNurb = gluNewNurbsRenderer();


  gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 25.0f);



  //...........................................................
  tst_gl1_line_attr ();


  gluBeginCurve(pNurb);

  gluNurbsCurve(pNurb,
        8, Knots,
        3,   // offset in ctrlPoints-array
        &ctrlPoints[0][0],
        4,        // degree + 1
        GL_MAP1_VERTEX_3);      // typ


  // typ muss fuer Begrenzungskurven GLU_MAP1_TRIM_2 sein !!
  // die ctrlPoints sind dann u/v-Werte und offset ist 2.



  // Done with surface
  gluEndCurve(pNurb);



  // display controlpoints yellow
  tst_gl1_point_f ((GLfloat*)ctrlPoints, 4, 3, (GLfloat*)&colTab[COL_YELLOW]);


  return 0;

}


//================================================================
  int tst_gl1_patch__ (Point *pTab, int pNr, int pTyp) {
//================================================================
// display triangles of OpenGL-patch

static int ti=0;

  int      irc, i1, tNr;
  // Triangle *triTab;


  printf("tst_gl1_patch__ ti=%d\n",ti);


  // get tNr = nr of triangles for this patch
  tNr = UTRI_triaNr_patch (pNr, pTyp);
  if(tNr < 1) {printf("***** tst_gl1_patch__ E001\n"); return -1;}


  // get space for <tNr> triangles
  // triTab = (Triangle*) MEM_alloc_tmp (tNr * sizeof(Triangle));


  // get <tNr> triangles from patch (pTab, pNr, pTyp)
  tNr = TRI_MAX;
  irc = UTRI_ntria_patch (triTab, &tNr, pTab, pNr, pTyp);
  if(irc < 0) return -1;


  // display triangles
  for(i1=0; i1<tNr; ++i1) {
    GR_Disp_tria (&triTab[i1], 9);
    GR_Disp_triv  (&triTab[i1], 3, ti, -1);
    ++ti;
    // GR_Disp_tris (&triTab[i1], 8);
  }

  return 0;

}

 
//========================================================================
  int tst_gl1_point_d (Point *pTab, int pNr, GLfloat *glCol) {
//========================================================================
// draw pNr points into open glList 
  
  int   ii, ip;

  glDisable(GL_LIGHTING);
  
  glPointSize (5.0);
  
  // glColor3f(1.0, 1.0, 0.0);
  glColor3fv (glCol);
  
  glBegin(GL_POINTS);
  for(ii=0; ii<pNr; ++ii) {
      // printf(" pt[%d]= %f %f %f\n",ip,pTab[ip], pTab[ip+1], pTab[ip+2]);
    glVertex3dv ((double*)&pTab[ii]);
  }
  glEnd();

  glEnable(GL_LIGHTING);


  return 0;

}


//========================================================================
  int tst_gl1_point_f (GLfloat *pTab, int pNr, int ptSiz, GLfloat *glCol) {
//========================================================================
// draw pNr points into open glList 

  int   ii, ip;

  glDisable(GL_LIGHTING);

  glPointSize(5.0);

  // glColor3f(1.0, 1.0, 0.0);
  glColor3fv (glCol);

  glBegin(GL_POINTS);
  ip = 0;
  for(ii=0; ii<pNr; ++ii) {
      printf(" pt[%d]= %f %f %f\n",ip,pTab[ip], pTab[ip+1], pTab[ip+2]);
    glVertex3f (pTab[ip], pTab[ip+1], pTab[ip+2]);
    ip += ptSiz;
  }
  glEnd();

  glEnable(GL_LIGHTING);


  return 0;

}


//================================================================
  int tst_gl1_sur_matl () {
//================================================================

  GLfloat mat_diffuse[] = { 0.7, 0.7, 0.7, 1.0 };
  GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
  GLfloat mat_shininess[] = { 100.0 };


  
  glColor3fv ((GLfloat*)&colTab[COL_SUR]);

  glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

  // glEnable(GL_LIGHT0);


}


//=========================================================
  int tst_gl1_nurbSur2 () {    
//=========================================================
// see redbook/surfpoints.c
// - cannot test if a tesselated point (out in GLU_NURBS_VERTEX(_DATA))
//   belong to an outer or inner boundary (given by gluPwlCurve)
// Problem gluPwlCurve: you have nearly always tesselatation errors,
//   from triangles at the boundary normal to its neighbour, caused by
//   points inside surface to near to the boundary !


  // NURBS object pointer
  GLUnurbsObj *pNurb = NULL;

  // The number of control points for this curve
  GLint nNumPoints = 4; // 4 X 4
    
  // Mesh extends four units -6 to +6 along x and y axis
  // Lies in Z plane
  //                 u  v  (x,y,z)
  GLfloat ctrlPoints[4][4][3]=
               {{{  -6.f, -6.f, 0.0f},  // u = 0, v = 0
                {   -6.f, -2.f, 0.0f},  //      v = 1
                {   -6.f,  2.f, 0.0f},  //      v = 2
                {   -6.f,  6.f, 0.0f}}, //      v = 3

                {{  -2.0f, -6.f, 0.0f},  // u = 1  v = 0
                {   -2.0f, -2.f, 8.f},  //      v = 1
                {   -2.0f,  2.f, 8.f},  //      v = 2
                {   -2.0f,  6.f, 0.0f}}, //      v = 3

                {{   2.0f, -6.f, 0.0f }, // u =2   v = 0
                {    2.0f, -2.f, 8.f }, //      v = 1
                {    2.0f,  2.0f, 8.f }, //      v = 2
                {    2.0f,  6.0f, 0.0f }},//      v = 3

                {{   6.0f, -6.0f, 0.0f},  // u = 3  v = 0
                {    6.0f, -2.0f, 0.0f},  //      v = 1
                {    6.0f,  2.0f, 0.0f},  //      v = 2
                {    6.0f,  6.0f, 0.0f}}};//      v = 3

  // Knont sequence for the NURB
  GLfloat Knots[8] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};

  // Outside trimming points to include entire surface
  // Begrenzungskurven; alle Werte sind u und v-Werte zwischen 0 und 1.
  GLfloat outsidePts[8][2] = /* counter clockwise */
    {{0.0f, 0.0f},
     {0.7f, 0.0f},
     {0.78f, 0.25f},
     {0.85f, 0.50f},
     {0.92f, 0.75f},
     {1.0f, 1.0f},
     {0.0f, 1.0f},
     {0.0f, 0.0f}};

  // Inside trimming points to create triangle shaped hole in surface
  GLfloat insidePts[7][2] = /* clockwise */
    {{0.25f, 0.25f},
     {0.35f, 0.40f},
     {0.50f, 0.50f},
     {0.62f, 0.40f},
     {0.71f, 0.25f},
     {0.50f, 0.25f},
     {0.25f, 0.25f}};

  GLfloat insideCCW[7][2] = /* counterclockwise */
    {{0.25f, 0.25f},
     {0.50f, 0.25f},
     {0.71f, 0.25f},
     {0.62f, 0.40f},
     {0.50f, 0.50f},
     {0.35f, 0.40f},
     {0.25f, 0.25f}};


  //-------------------------------------------------------------
  // // display controlpoints yellow
  // tst_gl1_point_f ((GLfloat*)ctrlPoints, 16, 3, (GLfloat*)&colTab[COL_YELLOW]);


  //-------------------------------------------------------------
  // Automatically generate normals for evaluated surfaces
  // init()
  glEnable(GL_LIGHTING);
  glEnable(GL_AUTO_NORMAL);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);

  // Setup the Nurbs object
  pNurb = gluNewNurbsRenderer();

  gluNurbsCallback (pNurb, GLU_ERROR,        (void*)&GLCB_error);
  gluNurbsCallback (pNurb, GLU_NURBS_BEGIN,  (void*)&GLCB_begin);
  gluNurbsCallback (pNurb, GLU_NURBS_VERTEX, (void*)&GLCB_vertex);
  // gluNurbsCallback (pNurb, GLU_NURBS_VERTEX_DATA, (void*)&GLCB_vert_dat);
  // gluNurbsCallback (pNurb, GLU_NURBS_NORMAL, (void*)&GLCB_normal);
  gluNurbsCallback (pNurb, GLU_NURBS_END,    (void*)&GLCB_end);


  //----------------------------------------------------------------
  gluNurbsProperty(pNurb, GLU_NURBS_MODE,         GLU_NURBS_TESSELLATOR);

  // gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 95.0f); // less=finer
  // value = # of pixels

  // gluNurbsProperty(pNurb, GLU_SAMPLING_METHOD, GLU_PARAMETRIC_ERROR);
  // gluNurbsProperty(pNurb, GLU_PARAMETRIC_TOLERANCE, 50.0f);

  // gluNurbsProperty(pNurb, GLU_SAMPLING_METHOD, GLU_PATH_LENGTH);
  // gluNurbsProperty(pNurb, GLU_SAMPLING_METHOD, GLU_OBJECT_PATH_LENGTH);
  // gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 5.0f);
  // value = # of pixels, less=finer

  gluNurbsProperty(pNurb, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE);
  gluNurbsProperty(pNurb, GLU_U_STEP, 3);   // nr of sample-points in U
  gluNurbsProperty(pNurb, GLU_V_STEP, 3);


  // GLU_DISPLAY_MODE: define type of result: boundarycurve, triangles, shaded

  // display faces (triangles):
  // gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);

  // display face-boundaries only:
  // gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_PATCH);

  // display shaded:
  gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, (GLfloat)GLU_FILL);

  // tst_gl1_sur_matl ();


  //----------------------------------------------------------------
  // Render the NURB
  // Begin the NURB definition
  gluBeginSurface(pNurb);


  // Evaluate the surface
  gluNurbsSurface (pNurb,  // pointer to NURBS renderer
        8, Knots,     // No. of knots and knot array u direction
        8, Knots,     // No. of knots and knot array v direction
        4 * 3,        // Distance between control points in u dir.
        3,            // Distance between control points in v dir.
        &ctrlPoints[0][0][0], // Control points
        4, 4,         // u and v order of surface
        GL_MAP2_VERTEX_3);    // Type of surface



  //----------------------------------------------------------------
  // Trim with outer-boundary; curve is U/V-parameters !
  gluBeginTrim (pNurb);
  // gluNurbsCallbackData (pNurb, outsidePts);
  gluPwlCurve (pNurb, 8, &outsidePts[0][0], 2, GLU_MAP1_TRIM_2);
  gluEndTrim (pNurb);
    // printf(" outsidePts=%p\n",outsidePts);


  //----------------------------------------------------------------
  // inner-boundary MUST have outer-boudary before !
  gluBeginTrim (pNurb);
  // gluNurbsCallbackData (pNurb, insidePts);
  gluPwlCurve (pNurb, 7, &insidePts[0][0], 2, GLU_MAP1_TRIM_2);  // OK !
  // gluPwlCurve (pNurb, 7, &insideCCW[0][0], 2, GLU_MAP1_TRIM_2);
  gluEndTrim (pNurb);
    // printf(" insidePts=%p\n",insidePts);


  //----------------------------------------------------------------
  // Done with surface; tesselate ..
  gluEndSurface (pNurb);


  // delete
  // gluDeleteNurbsRenderer (pNurb);


  return 0;
}


//=========================================================
  int tst_gl1_nurbSur1 () {
//=========================================================
// tolerances from view-scale !



  // NURBS object pointer
  GLUnurbsObj *pNurb = NULL;

  // The number of control points for this curve
  GLint nNumPoints = 4; // 4 X 4

  // Mesh extends four units -6 to +6 along x and y axis
  // Lies in Z plane
  //                 u  v  (x,y,z)
  GLfloat ctrlPoints[4][4][3]=
               {{{  -6.f, -6.f, 0.0f},  // u = 0, v = 0
                {   -6.f, -2.f, 0.0f},  //      v = 1
                {   -6.f,  2.f, 0.0f},  //      v = 2
                {   -6.f,  6.f, 0.0f}}, //      v = 3

                {{  -2.0f, -6.f, 0.0f},  // u = 1  v = 0
                {   -2.0f, -2.f, 8.f},  //      v = 1
                {   -2.0f,  2.f, 8.f},  //      v = 2
                {   -2.0f,  6.f, 0.0f}}, //      v = 3

                {{   2.0f, -6.f, 0.0f }, // u =2   v = 0
                {    2.0f, -2.f, 8.f }, //      v = 1
                {    2.0f,  2.0f, 8.f }, //      v = 2
                {    2.0f,  6.0f, 0.0f }},//      v = 3

                {{   6.0f, -6.0f, 0.0f},  // u = 3  v = 0
                {    6.0f, -2.0f, 0.0f},  //      v = 1
                {    6.0f,  2.0f, 0.0f},  //      v = 2
                {    6.0f,  6.0f, 0.0f}}};//      v = 3



  // Knont sequence for the NURB
  GLfloat Knots[8] = {0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f};


  // Outside trimming points to include entire surface
  // Begrenzungskurven; alle Werte sind u und v-Werte zwischen 0 und 1.
  GLfloat outsidePts[5][2] = /* counter clockwise */
    {{0.0f, 0.0f},
     {0.7f, 0.0f},
     {1.0f, 1.0f},
     {0.0f, 1.0f},
     {0.0f, 0.0f}};


  // Inside trimming points to create triangle shaped hole in surface
  GLfloat insidePts[7][2] = /* clockwise */
    {{0.25f, 0.25f},
     {0.35f, 0.40f},
     {0.50f, 0.50f},
     {0.62f, 0.40f},
     {0.71f, 0.25f},
     {0.50f, 0.25f},
     {0.25f, 0.25f}};


  GLfloat insideCCW[4][2] = /* counterclockwise */
    {{0.25f, 0.25f},
     {0.75f, 0.25f},
     {0.5f,  0.5f},
     {0.25f, 0.25f}};





  //-------------------------------------------------------------
  // display controlpoints yellow
  tst_gl1_point_f ((GLfloat*)ctrlPoints, 16, 3, (GLfloat*)&colTab[COL_YELLOW]);



  //-------------------------------------------------------------
  // Automatically generate normals for evaluated surfaces
  glEnable(GL_AUTO_NORMAL);
  glEnable(GL_DEPTH_TEST);
  glEnable(GL_NORMALIZE);



  // Setup the Nurbs object
  pNurb = gluNewNurbsRenderer();

  gluNurbsCallback (pNurb, GLU_ERROR, (void*)&GLCB_error);


  // gluNurbsProperty(pNurb, GLU_SAMPLING_TOLERANCE, 25.0f);
  // mit Wert 25 wirds viel feiner tesseliert ..


  gluNurbsProperty(pNurb, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE);
  gluNurbsProperty(pNurb, GLU_U_STEP, 5);   // nr of sample-points in U
  gluNurbsProperty(pNurb, GLU_V_STEP, 5);



  //----------------------------------------------------------------
  // define type of result: boundarycurve, triangles, shaded

  // display faces (triangles):
  gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON);

  // display face-boundaries only:
  // gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, GLU_OUTLINE_PATCH);

  // display shaded:
  // gluNurbsProperty(pNurb, GLU_DISPLAY_MODE, (GLfloat)GLU_FILL);

 


  tst_gl1_sur_matl ();

  glEnable (GL_LIGHTING);



  //----------------------------------------------------------------
  // Render the NURB
  // Begin the NURB definition
  gluBeginSurface(pNurb);


  // Evaluate the surface
  gluNurbsSurface(pNurb,  // pointer to NURBS renderer
        8, Knots,     // No. of knots and knot array u direction
        8, Knots,     // No. of knots and knot array v direction
        4 * 3,        // Distance between control points in u dir.
        3,            // Distance between control points in v dir.
        &ctrlPoints[0][0][0], // Control points
        4, 4,         // u and v order of surface
        GL_MAP2_VERTEX_3);    // Type of surface


  //----------------------------------------------------------------
  // Trim with outer-boundary; curve is U/V-parameters !
  gluBeginTrim (pNurb);
  gluPwlCurve (pNurb, 5, &outsidePts[0][0], 2, GLU_MAP1_TRIM_2);
  gluEndTrim (pNurb);


  //----------------------------------------------------------------
  // Begrenzungskurve
  gluBeginTrim (pNurb);
  gluPwlCurve (pNurb, 7, &insidePts[0][0], 2, GLU_MAP1_TRIM_2);
  // gluPwlCurve (pNurb, 4, &insideCCW[0][0], 2, GLU_MAP1_TRIM_2);
  gluEndTrim (pNurb);


  // Done with surface; tesselate ..
  gluEndSurface(pNurb);


  // delete
  gluDeleteNurbsRenderer (pNurb);


  return 0;
}


//=========================================================
  int tst_gl1_bezSur () {
//=========================================================


  // The number of control points for this curve
  GLint nNumPoints = 3;

  GLfloat ctrlPoints[3][3][3]=
               {{{  -4.0f, 0.0f, 4.0f},
                  { -2.0f, 4.0f, 4.0f},
                {  4.0f, 0.0f, 4.0f }},

                {{  -4.0f, 0.0f, 0.0f},
                  { -2.0f, 4.0f, 0.0f},
                {  4.0f, 0.0f, 0.0f }},

                {{  -4.0f, 0.0f, -4.0f},
                  { -2.0f, 4.0f, -4.0f},
                {  4.0f, 0.0f, -4.0f }}};



  //----------------------------------------------------------------
  // Automatically generate normals for evaluated surfaces
  glEnable(GL_AUTO_NORMAL);

  glEnable (GL_LIGHTING);

  glColor3fv ((GLfloat*)&colTab[COL_RED]);

 
  // Sets up the Bezier
  // This actually only needs to be called once and could go in
  // the setup function
  glMap2f(GL_MAP2_VERTEX_3, // Type of data generated
  0.0f,           // Lower u range
  10.0f,          // Upper u range
  3,              // Distance between points in the data
  3,              // Dimension in u direction (order)
  0.0f,           // Lower v range
  10.0f,          // Upper v range
  9,              // Distance between points in the data
  3,              // Dimension in v direction (order)
  &ctrlPoints[0][0][0]);    // array of control points

  // Enable the evaluator
  glEnable(GL_MAP2_VERTEX_3);

  // Use higher level functions to map to a grid, then evaluate the
  // entire thing.

  // Map a grid of 10 points from 0 to 10
  glMapGrid2f(10,0.0f,10.0f,10,0.0f,10.0f);




  //...........................................................
  // Evaluate the grid, using lines
  // glEvalMesh2(GL_LINE,0,10,0,10);
  glEvalMesh2(GL_FILL,0,10,0,10);


  //-------------------------------------------------------------
  // display controlpoints yellow
  tst_gl1_point_f ((GLfloat*)ctrlPoints, 9, 3, (GLfloat*)&colTab[COL_YELLOW]);



  return 0;
}


//================================================================
  int tst_gl1_bezCurv () {
//================================================================
// test bezier-curve
// test rational-bezier-curve

  long        i1;
  Point       pt1;
  float       f1, fpp[100];

  GLfloat ctrlPoints[4][4]  =
              {{  -6.0f, -6.0f, 0.0f, 1.0f},
               {   2.0f, -2.0f, 8.0f, 1.0f},
               {   2.0f,  6.0f, 0.0f, 1.0f},
               {   6.0f, 6.0f,  0.0f, 1.0f}};



  //...........................................................
  tst_gl1_line_attr ();


  //...........................................................
  // glEnable (GL_MAP1_VERTEX_3);
  glEnable (GL_MAP1_VERTEX_4);



  // setup curve
  // glMap1f (GL_MAP1_VERTEX_3,
  glMap1f (GL_MAP1_VERTEX_4,
           0.0f,
           1.0f,
           4,
           4,
           (void*)ctrlPoints);

  // draw curve
/*
  glBegin (GL_LINE_STRIP);
  for(f1 = 0.f; f1 <= 1.05f; f1 += 0.1f) {
     glEvalCoord1f ((GLfloat)f1);
  }
  glEnd ();
*/

  // evaluate all points
  glMapGrid1d (10, 0., 1.);

  // // get controlpoints
  // glGetMapfv (GL_MAP1_VERTEX_4, GL_COEFF, fpp);
  // for(i1=0; i1<30; ++i1) { // printf(" [%ld]%f\n",i1,fpp[i1]); // }
              

  // display curve
  glEvalMesh1 (GL_LINE, 0, 10);


  //-------------------------------------------------------------
  // display controlpoints yellow
  tst_gl1_point_f ((GLfloat*)ctrlPoints, 4, 4, (GLfloat*)&colTab[COL_YELLOW]);



  return 0;

}





//================================================================
  int tst_gl1_line_attr () {
//================================================================
 
  glColor3fv ((GLfloat*)&colTab[COL_RED]);
  glLineWidth (3.f);    // min = 1.

  glEnable (GL_LINE_STIPPLE);
  glLineStipple (3, 16377);

  return 0;

}


//=========================================================
  int tst_gl1_ln () {
//=========================================================


  Point  p1={-1.,0.,0.};
  Point  p2={2.,0.,2.};


  //----------------------------------------------------------------
  tst_gl1_line_attr ();


  glBegin (GL_LINES);
    glVertex3d (p1.x, p1.y, p1.z);
    glVertex3d (p2.x, p2.y, p2.z);
  glEnd ();

  glDisable (GL_LINE_STIPPLE); 

  return 0;
}



//=========================================================
  int gCad_fini () {
//=========================================================

  AP_User_reset ();

  return 0;
}




//=========================================================
  int gCad_main () {
//=========================================================


  long   dli;
  Point  p1={10.,0.,0.};
  Point  p2={20.,0.,0.};
  GLuint dlInd;


  TX_Print(">>>>>>>>> gCad_main aus tst_gl1 <<<<<<<<<<\n");

  tst_gl1 ();

  DL_Redraw ();

  gCad_fini ();

  return 0;
}


//=========================================================
  int tst_gl1 () {
//=========================================================

  long   dli;
  GLuint dlInd;


  dli = -1;
  dlInd = GL_fix_DL_ind (&dli);

  glNewList (dlInd, GL_COMPILE);



  //...........................................................
  // gl_light1 ();

  // tst_gl1_ln (); // Test: draw Line

  // tst_gl1_bezCurv (); // test bezier-curve

  // tst_gl1_bezSur (); // BezierSurface

  // tst_gl1_nurbCrv (); // NurbsCurve

  // tst_gl1_nurbSur1 (); // NurbsSurface

  tst_gl1_nurbSur2 (); // NurbsSurface with callbacks


  //...........................................................
  glEndList ();



  return 0;
}

/*
//================================================================
  int UTRI_triaNr_patch (int ptNr, int patchTyp) {
//================================================================
/// \code
/// UTRI_triaNr_patch     get nr of triangles for opengl-patch
/// Input:
///   ptNr     nr of points
///   patchTyp GL_TRIANGLE_STRIP|GL_TRIANGLE_FAN|GL_QUAD_STRIP
///
/// see TSU_facNr_ipatch
/// see tess_triaNr_patch
/// \endcode

  int   tNr;


    switch (patchTyp) {

      case GL_TRIANGLES:
        tNr = ptNr / 3;
        break;

      case GL_TRIANGLE_STRIP:
      case GL_FAC_PLANAR:
      case GL_TRIANGLE_FAN:
      case GL_QUAD_STRIP:
        tNr = ptNr - 2;
        break;

      default:
        TX_Error("UTRI_triaNr_patch NYI typ=%d",patchTyp);
        return -1;
    }


    // printf("ex UTRI_triaNr_patch %d\n",tNr);


  return tNr;

}


//=======================================================================
  int UTRI_ntria_patch (Triangle *tTab, int *tSiz,
                        Point *pTab, int pNr, int pTyp) {
//=======================================================================
// get triangles from opengl-patch (pTab, pNr, pTyp)
// Input:
//   tSiz   size of tTab
//   pTyp   patchTyp GL_TRIANGLE_STRIP|GL_TRIANGLE_FAN|GL_QUAD_STRIP
// Output:
//   tSiz   nr of Triangles created
// 
// find min size of tTab: UTRI_triaNr_patch()
// see TSU_nfac_ipatch__


  int      i1, ii, tNr;
  

  ii = 0;


  switch (pTyp) {

    //================================================================
    case GL_TRIANGLES:  // 4

      tNr = pNr / 3;           // total nr of triangles
      if(tNr > *tSiz) goto L_errEOM;

      L_T0:
        tTab->pa[0] = pTab;  ++pTab;
        tTab->pa[1] = pTab;  ++pTab;
        tTab->pa[2] = pTab;  ++pTab;
        ++tTab;
        ++ii;
        if(ii < tNr) goto L_T0;

      break;


    //================================================================
    case GL_FAC_PLANAR:      // 16:   Achtung: additinal for indexed 
    case GL_TRIANGLE_FAN:    // 6
      //    1------2           ptAnz = 4
      //    |    /  |
      //    |   /   |
      //    |  /    |
      //    | /     |
      //    0.------3
      //      \     /
      //        \  /
      //         4
      //
      // sollte so zerlegt werden:
      // 0 1 2
      // 0 2 3
      // 0 3 4

      tNr = pNr - 2;
      if(tNr > *tSiz) goto L_errEOM;
      i1 = 1;

      L_T6:
        tTab->pa[0] = &pTab[0];
        tTab->pa[1] = &pTab[i1]; ++i1;
        tTab->pa[2] = &pTab[i1];
        ++tTab;
        ++ii;
        if(ii < tNr) goto L_T6;

      break;



    //================================================================
    case GL_TRIANGLE_STRIP:  // 5
    case GL_QUAD_STRIP:      // 8
      //
      //    0--2--4--6
      //    | /| /| /|
      //    |/ |/ |/ |
      //    1--3--5--7
      //
      // sollte so zerlegt werden:
      // 0 1 2
      // 2 1 3
      // 2 3 4
      // 4 3 5 ..

      tNr = pNr - 2;
      if(tNr > *tSiz) goto L_errEOM;
      i1 = 0;

      L_T8:
        tTab->pa[0] = &pTab[i1]; ++i1;
        tTab->pa[1] = &pTab[i1]; ++i1;
        tTab->pa[2] = &pTab[i1];
        ++tTab;
        ++ii;
        if(ii >= tNr) break;

        tTab->pa[0] = &pTab[i1]; 
        tTab->pa[1] = &pTab[i1-1];
        tTab->pa[2] = &pTab[i1+1];
        ++tTab;
        ++ii;
        if(ii < tNr) goto L_T8;

      break;




    //================================================================
    default:
      TX_Error("UTRI_ntria_patch E001 %d", pTyp);
      return -1;

  }

  *tSiz = tNr;

  return 0;



  L_errEOM:
    TX_Error("UTRI_ntria_patch EOM");
    return -1;



  return 0;

}
*/

//======================== EOF ======================
