"Fossies" - the Fresh Open Source Software Archive

Member "gfsview-snapshot-121130/gl/gfsgl2D.h" (30 Nov 2012, 26188 Bytes) of package /linux/privat/gfsview-snapshot-121130.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gfsgl2D.h" see the Fossies "Dox" file reference documentation.

    1 /* Gerris - The GNU Flow Solver
    2  * Copyright (C) 2001-2004 National Institute of Water and Atmospheric
    3  * Research
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License as
    7  * published by the Free Software Foundation; either version 2 of the
    8  * License, or (at your option) any later version.
    9  *
   10  * This program is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   13  * General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU General Public License
   16  * along with this program; if not, write to the Free Software
   17  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   18  * 02111-1307, USA.  
   19  */
   20 
   21 /* GfsGlCells: Object */
   22 
   23 static void gl_cell (FttCell * cell, GfsGl * gl)
   24 {
   25   FttVector p;
   26   gdouble size = ftt_cell_size (cell)/2.;
   27   
   28   ftt_cell_pos (cell, &p);
   29   glBegin (GL_LINE_LOOP);
   30   glVertex2d (p.x - size, p.y - size);
   31   glVertex2d (p.x + size, p.y - size);
   32   glVertex2d (p.x + size, p.y + size);
   33   glVertex2d (p.x - size, p.y + size);
   34   glEnd ();
   35   gl->size++;
   36 }
   37 
   38 /* GfsGlSquares: Object */
   39 
   40 static void gl_square (FttCell * cell, GfsGl * gl)
   41 {
   42   GfsGlScalar * gls = GFS_GL_SCALAR (gl);
   43   if (!GFS_HAS_DATA (cell, gls->v))
   44     return;
   45   FttVector p;
   46   gdouble size = ftt_cell_size (cell)/1.999;
   47   GtsColor c;
   48 
   49   gl->size++;
   50   ftt_cell_pos (cell, &p);
   51   c = gfs_colormap_color (gls->cmap, gls->max > gls->min ?
   52               (GFS_VALUE (cell, gls->v) - gls->min)/(gls->max - gls->min) :
   53               0.5);
   54   glColor3f (c.r, c.g, c.b);
   55   glVertex2d (p.x - size, p.y - size);
   56   glVertex2d (p.x + size, p.y - size);
   57   glVertex2d (p.x + size, p.y + size);
   58   glVertex2d (p.x - size, p.y + size);
   59 }
   60 
   61 static void gl_squares_draw (GfsGl * gl, GfsFrustum * f)
   62 {
   63   gl->size = 0;
   64   glBegin (GL_QUADS);
   65   gfs_gl_normal (gl);
   66   gfs_gl_cell_traverse_visible_plane (gl, f, (FttCellTraverseFunc) gl_square, gl);
   67   glEnd ();
   68 
   69   (* GFS_GL_CLASS (GTS_OBJECT (gl)->klass->parent_class)->draw) (gl, f);
   70 }
   71 
   72 /* GfsGlSolid: Object */
   73 
   74 #define CUT(d) (s->s[d] > 0. && s->s[d] < 1.)
   75 
   76 static void gl_solid (FttCell * cell, GfsGl * gl)
   77 {
   78   if (GFS_IS_MIXED (cell)) {
   79     GfsSolidVector * s = GFS_STATE (cell)->solid;
   80     guint n = 0;
   81     FttDirection d;
   82     FttVector c, p[4];
   83     gdouble h = ftt_cell_size (cell)/1.999;
   84     static guint etod[] = { 3, 0, 2, 1 };
   85     
   86     gl->size++;
   87     ftt_cell_pos (cell, &c);  
   88     p[0].x = c.x - h; p[0].y = c.y - h;
   89     p[1].x = c.x + h; p[1].y = c.y - h;
   90     p[2].x = c.x + h; p[2].y = c.y + h;
   91     p[3].x = c.x - h; p[3].y = c.y + h;
   92     
   93     for (d = 0; d < FTT_NEIGHBORS; d++)
   94       if (s->s[d] > 0. && s->s[d] < 1.)
   95     n++;
   96     switch (n) {
   97     case 2: {
   98       guint k, m, n1 = 0;
   99       FttVector r[2];
  100       gboolean ins;
  101       static guint ctoc[4][2] = {{0,2},{2,1},{1,3},{3,0}};
  102       
  103       for (m = 0; m < 4 && !CUT (etod[m]); m++);
  104       ins = CUT (ctoc[m][0]) ? s->s[ctoc[m][1]] : (s->s[ctoc[m][0]] != 1.);
  105       for (k = m; k < m + 4; k++) {
  106     guint i = k % 4, i1 = (i + 1) % 4;
  107     if (CUT (etod[i])) {
  108       gdouble a = ins ? s->s[etod[i]] : 1. - s->s[etod[i]];
  109       r[n1].x = (1. - a)*p[i].x + a*p[i1].x;
  110       r[n1++].y = (1. - a)*p[i].y + a*p[i1].y;
  111       ins = !ins;
  112       if (n1 == 2) {
  113         glVertex2d (r[0].x, r[0].y);
  114         glVertex2d (r[1].x, r[1].y);
  115         n1 = 0;
  116       }
  117     }
  118       }
  119       break;
  120     }
  121     case 4:
  122       break;
  123     default:
  124 #if 0
  125       g_assert_not_reached ();
  126 #else
  127       {
  128     FttVector p;
  129     ftt_cell_pos (cell, &p);
  130     g_warning ("(%g,%g): %d", p.x, p.y, n);
  131       }
  132 #endif
  133     }
  134   }
  135 }
  136 
  137 static void gl_solid_draw (GfsGl * gl, GfsFrustum * f)
  138 {
  139   gl->size = 0;
  140   glMatrixMode (GL_PROJECTION);
  141   glPushMatrix ();
  142   glTranslatef (0., 0., gl->p->lc);
  143   glBegin (GL_LINES);
  144   glNormal3d (0., 0., 1.);
  145   gfs_gl_cell_traverse_visible_plane (gl, f, (FttCellTraverseFunc) gl_solid, gl);
  146   glEnd ();
  147   glPopMatrix ();
  148 }
  149 
  150 static void gl_solid_init (GfsGl * gl)
  151 {
  152   GtsColor c = { 0., 1., 0. };
  153 
  154   gl->lc = c;
  155 }
  156 
  157 static gboolean gl_solid_relevant (GfsSimulation * sim)
  158 {
  159   return (sim->solids->items != NULL);
  160 }
  161 
  162 static void gl_solid_class_init (GfsGlClass * klass)
  163 {
  164   klass->draw = gl_solid_draw;
  165   klass->relevant = gl_solid_relevant;
  166 }
  167 
  168 GfsGlClass * gfs_gl_solid_class (void)
  169 {
  170   static GfsGlClass * klass = NULL;
  171 
  172   if (klass == NULL) {
  173     GtsObjectClassInfo gfs_gl_solid_info = {
  174       "GfsGlSolid",
  175       sizeof (GfsGl),
  176       sizeof (GfsGlClass),
  177       (GtsObjectClassInitFunc) gl_solid_class_init,
  178       (GtsObjectInitFunc) gl_solid_init,
  179       (GtsArgSetFunc) NULL,
  180       (GtsArgGetFunc) NULL
  181     };
  182     klass = gts_object_class_new (GTS_OBJECT_CLASS (gfs_gl_class ()), &gfs_gl_solid_info);
  183   }
  184 
  185   return klass;
  186 }
  187 
  188 /* GfsGlFractions: Object */
  189 
  190 static void gl_fractions (FttCell * cell, GfsGl * gl)
  191 {
  192   GfsSolidVector * s = GFS_STATE (cell)->solid;
  193   FttVector c;
  194   gdouble h = ftt_cell_size (cell)*0.45;
  195   
  196   gl->size++;
  197   ftt_cell_pos (cell, &c);
  198   glVertex2d (c.x + h, c.y - h*s->s[0]);
  199   glVertex2d (c.x + h, c.y + h*s->s[0]);
  200   glVertex2d (c.x - h, c.y - h*s->s[1]);
  201   glVertex2d (c.x - h, c.y + h*s->s[1]);
  202   glVertex2d (c.x - h*s->s[2], c.y + h);
  203   glVertex2d (c.x + h*s->s[2], c.y + h);
  204   glVertex2d (c.x - h*s->s[3], c.y - h);
  205   glVertex2d (c.x + h*s->s[3], c.y - h);
  206 }
  207 
  208 static void gl_fractions_draw (GfsGl * gl, GfsFrustum * f)
  209 {
  210   gl->size = 0;
  211   glMatrixMode (GL_PROJECTION);
  212   glPushMatrix ();
  213   glTranslatef (0., 0., gl->p->lc);
  214   glBegin (GL_LINES);
  215   gfs_gl_cell_traverse_visible_mixed (gl, f, (FttCellTraverseFunc) gl_fractions, gl);
  216   glEnd ();
  217   glPopMatrix ();
  218 }
  219 
  220 /* GfsGlBoundaries: Object */
  221 
  222 static void gl_boundaries (FttCell * cell, GfsGl * gl)
  223 {
  224   if (!GFS_IS_MIXED (cell)) {
  225     FttDirection d;
  226     FttCellNeighbors n;
  227     gdouble h = ftt_cell_size (cell)/2.;
  228     FttVector p;
  229 
  230     ftt_cell_neighbors (cell, &n);
  231     ftt_cell_pos (cell, &p);
  232     for (d = 0; d < FTT_NEIGHBORS; d++)
  233       if (!n.c[d] || GFS_CELL_IS_BOUNDARY (n.c[d])) {
  234     static FttVector dp[FTT_NEIGHBORS][2] = {
  235       {{1.,-1.,0.},{1.,1.,0.}},
  236       {{-1.,1.,0.},{-1.,-1,0.}},
  237       {{1.,1.,0.},{-1.,1.,0.}},
  238       {{-1.,-1.,0.},{1.,-1.,0.}}
  239     };
  240     gl->size++;
  241     glVertex2d (p.x + dp[d][0].x*h, p.y + dp[d][0].y*h);
  242     glVertex2d (p.x + dp[d][1].x*h, p.y + dp[d][1].y*h);
  243       }
  244   }
  245 }
  246 
  247 /* GfsGlLevels: Object */
  248 
  249 /**
  250  * ftt_face_gl:
  251  * @face: a #FttCellFace.
  252  *
  253  * Creates an OpenGL representation of @face.  
  254  */
  255 static void ftt_face_gl (const FttCellFace * face)
  256 {
  257   gdouble size;
  258   FttVector p;
  259 #if FTT_2D
  260   static FttVector dp[FTT_NEIGHBORS][2] = {
  261     {{1.,-1.,0.},{1.,1.,0.}},
  262     {{-1.,1.,0.},{-1.,-1,0.}},
  263     {{1.,1.,0.},{-1.,1.,0.}},
  264     {{-1.,-1.,0.},{1.,-1.,0.}}
  265   };
  266 #else  /* FTT_3D */
  267   static FttVector dp[FTT_NEIGHBORS][4] = {
  268     {{1.,-1.,1.},{1.,-1.,-1.},{1.,1.,-1.},{1.,1.,1.}},
  269     {{-1.,-1.,1.},{-1.,-1.,-1.},{-1.,1.,-1.},{-1.,1.,1.}},
  270     {{1.,1.,1.},{1.,1.,-1.},{-1,1.,-1.},{-1.,1.,1.}},
  271     {{1.,-1.,1.},{1.,-1.,-1.},{-1,-1.,-1.},{-1.,-1.,1.}},
  272     {{1.,-1.,1.},{1.,1.,1.},{-1.,1.,1.},{-1.,-1.,1.}},
  273     {{1.,-1.,-1.},{1.,1.,-1.},{-1.,1.,-1.},{-1.,-1.,-1.}},
  274   };
  275 #endif /* FTT_3D */
  276 
  277   g_return_if_fail (face != NULL);
  278 
  279   size = ftt_cell_size (face->cell)/2.;
  280   ftt_cell_pos (face->cell, &p);
  281 #if FTT_2D
  282   glVertex2d (p.x + dp[face->d][0].x*size, p.y + dp[face->d][0].y*size);
  283   glVertex2d (p.x + dp[face->d][1].x*size, p.y + dp[face->d][1].y*size);
  284 #else  /* FTT_3D */
  285 #if 0
  286   fprintf (fp, 
  287        "OFF 4 1 4 "
  288        "%g %g %g "
  289        "%g %g %g "
  290        "%g %g %g "
  291        "%g %g %g "
  292        "4 0 1 2 3\n",
  293        p.x + dp[face->d][0].x*size,
  294        p.y + dp[face->d][0].y*size,
  295        p.z + dp[face->d][0].z*size,
  296        p.x + dp[face->d][1].x*size,
  297        p.y + dp[face->d][1].y*size,
  298        p.z + dp[face->d][1].z*size,
  299        p.x + dp[face->d][2].x*size,
  300        p.y + dp[face->d][2].y*size,
  301        p.z + dp[face->d][2].z*size,
  302        p.x + dp[face->d][3].x*size,
  303        p.y + dp[face->d][3].y*size,
  304        p.z + dp[face->d][3].z*size);
  305 #endif
  306 #endif /* FTT_3D */
  307 }
  308 
  309 static void gl_face (FttCell * cell, GfsGlLevels * gl)
  310 {
  311   FttCellNeighbors n;
  312   FttCellFace f;
  313   gboolean drawn = FALSE;
  314 
  315   ftt_cell_neighbors (cell, &n);
  316   f.cell = cell;
  317   for (f.d = 0; f.d < FTT_NEIGHBORS; f.d++) {
  318     f.neighbor = n.c[f.d];
  319     if (f.neighbor &&
  320     floor (GFS_VALUE (cell, gl->v)) != 
  321     floor (GFS_VALUE (f.neighbor, gl->v))) {
  322       ftt_face_gl (&f);
  323       drawn = TRUE;
  324     }
  325   }
  326   if (drawn)
  327     GFS_GL (gl)->size++;
  328 }
  329 
  330 /* GfsGlVectors: Object */
  331 
  332 static void gl_vector (FttCell * cell, GfsGl * gl)
  333 {
  334   GfsGlVectors * gls = GFS_GL_VECTORS (gl);
  335   if (gls->use_scalar && !GFS_HAS_DATA (cell, GFS_GL_SCALAR (gl)->v))
  336     return;
  337 
  338   FttComponent c;
  339   FttVector pos, f;
  340 
  341   gl->size++;
  342   if (gls->use_scalar) {
  343     GfsGlScalar * gla = GFS_GL_SCALAR (gl);
  344     GtsColor c = gfs_colormap_color (gla->cmap, gla->max > gla->min ?
  345                      (GFS_VALUE (cell, gla->v) - gla->min)/
  346                      (gla->max - gla->min) :
  347                      0.5);
  348     glColor3f (c.r, c.g, c.b);
  349   }
  350   gfs_cell_cm (cell, &pos);
  351   for (c = 0; c < FTT_DIMENSION; c++)
  352     (&f.x)[c] = GFS_VALUE (cell, gls->v[c]);
  353   f.x *= gls->scale;
  354   f.y *= gls->scale;
  355   glVertex2d (pos.x + f.x - (f.x - f.y/2.)/5., pos.y + f.y - (f.x/2. + f.y)/5.);
  356   glVertex2d (pos.x + f.x, pos.y + f.y);
  357   glVertex2d (pos.x + f.x, pos.y + f.y);
  358   glVertex2d (pos.x + f.x - (f.x + f.y/2.)/5., pos.y + f.y + (f.x/2. - f.y)/5.);
  359   glVertex2d (pos.x, pos.y);
  360   glVertex2d (pos.x + f.x, pos.y + f.y);
  361 }
  362 
  363 /* GfsGlEllipses: Object */
  364 
  365 static void gl_ellipse (FttCell * cell, GfsGl * gl)
  366 {
  367   GfsGlEllipses * gls = GFS_GL_ELLIPSES (gl);
  368   if (gls->use_scalar && !GFS_HAS_DATA (cell, GFS_GL_SCALAR (gl)->v))
  369     return;
  370   FttVector pos;
  371   gdouble t;
  372 
  373   gl->size++;
  374   if (gls->use_scalar) {
  375     GfsGlScalar * gla = GFS_GL_SCALAR (gl);
  376     GtsColor c = gfs_colormap_color (gla->cmap, gla->max > gla->min ?
  377                      (GFS_VALUE (cell, gla->v) - gla->min)/
  378                      (gla->max - gla->min) :
  379                      0.5);
  380     glColor3f (c.r, c.g, c.b);
  381   }
  382   gfs_cell_cm (cell, &pos);
  383   glBegin (GL_LINE_LOOP);
  384   for (t = 0.; t < 2.*M_PI; t += 2.*M_PI/20.) {
  385     gdouble cost = cos (t), sint = sin (t);
  386 
  387     glVertex2d (pos.x + gls->scale*(GFS_VALUE (cell, gls->v[0])*cost + 
  388                     GFS_VALUE (cell, gls->v[2])*sint),
  389         pos.y + gls->scale*(GFS_VALUE (cell, gls->v[1])*cost + 
  390                     GFS_VALUE (cell, gls->v[3])*sint));
  391   }
  392   glEnd ();
  393 }
  394 
  395 /* GfsGlLocate: Object */
  396 
  397 static void gl_locate (FttCell * cell, GfsGl * gl)
  398 {
  399   gl_cell (cell, gl);
  400 }
  401 
  402 /* GfsGlLinear: Object */
  403 
  404 #define param(v) (gls->max > gls->min ? ((v) - gls->min)/(gls->max - gls->min) : 0.5)
  405 #define color(v) (gfs_colormap_color (gls->cmap, param (v)))
  406 
  407 static void gl_linear_color_constant (FttCell * cell, GfsGl * gl)
  408 {
  409   GfsGlScalar * gls = GFS_GL_SCALAR (gl);
  410   if (!GFS_HAS_DATA (cell, gls->v))
  411     return;
  412   FttVector p;
  413   gdouble v, size = ftt_cell_size (cell)/1.999;
  414   GtsColor c;
  415   FttDirection d[2];
  416 
  417   gl->size++;
  418   ftt_cell_pos (cell, &p);
  419   d[0] = FTT_LEFT; d[1] = FTT_BOTTOM;
  420   v = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  421   c = color (v);
  422   glColor3f (c.r, c.g, c.b);
  423   glVertex2d (p.x - size, p.y - size);
  424   d[0] = FTT_RIGHT; d[1] = FTT_BOTTOM;
  425   v = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  426   c = color (v);
  427   glColor3f (c.r, c.g, c.b);
  428   glVertex2d (p.x + size, p.y - size);
  429   d[0] = FTT_RIGHT; d[1] = FTT_TOP;
  430   v = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  431   c = color (v);
  432   glColor3f (c.r, c.g, c.b);
  433   glVertex2d (p.x + size, p.y + size);
  434   d[0] = FTT_LEFT; d[1] = FTT_TOP;
  435   v = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  436   c = color (v);
  437   glColor3f (c.r, c.g, c.b);
  438   glVertex2d (p.x - size, p.y + size);
  439 }
  440 
  441 static void gl_linear_texture_constant (FttCell * cell, GfsGl * gl)
  442 {
  443   GfsGlScalar * gls = GFS_GL_SCALAR (gl);
  444   if (!GFS_HAS_DATA (cell, gls->v))
  445     return;
  446   FttVector p;
  447   gdouble v1, v2, v3, v4, p1, p2, p3, p4;
  448   gdouble size = ftt_cell_size (cell)/1.999;
  449   FttDirection d[2];
  450 
  451   gl->size++;
  452   ftt_cell_pos (cell, &p);
  453 
  454   d[0] = FTT_LEFT; d[1] = FTT_BOTTOM;
  455   v1 = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  456   p1 = param (v1);
  457   d[0] = FTT_RIGHT; d[1] = FTT_BOTTOM;
  458   v2 = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  459   p2 = param (v2);
  460   d[0] = FTT_RIGHT; d[1] = FTT_TOP;
  461   v3 = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  462   p3 = param (v3);
  463   d[0] = FTT_LEFT; d[1] = FTT_TOP;
  464   v4 = gfs_cell_corner_value (cell, d, gls->v, gl->maxlevel);
  465   p4 = param (v4);
  466 
  467   glBegin (GL_TRIANGLE_FAN);
  468   glTexCoord1d ((p1 + p2 + p3 + p4)/4.);
  469   glVertex2d (p.x, p.y);
  470   glTexCoord1d (p1);
  471   glVertex2d (p.x - size, p.y - size);
  472   glTexCoord1d (p2);
  473   glVertex2d (p.x + size, p.y - size);
  474   glTexCoord1d (p3);
  475   glVertex2d (p.x + size, p.y + size);
  476   glTexCoord1d (p4);
  477   glVertex2d (p.x - size, p.y + size);
  478   glTexCoord1d (p1);
  479   glVertex2d (p.x - size, p.y - size);
  480   glEnd ();
  481 }
  482 
  483 typedef struct {
  484   gdouble p, z;
  485   FttVector n;
  486 } Vertex;
  487 
  488 static void new_vertex (FttCell * cell, FttDirection * d, GfsGl * gl, Vertex * v)
  489 {
  490   GfsGlScalar * gls = GFS_GL_SCALAR (gl);
  491   GfsGlLinear * gll = GFS_GL_LINEAR (gl);
  492   GfsInterpolator inter;
  493   gfs_cell_corner_interpolator (cell, d, gl->maxlevel, FALSE, &inter);
  494   gdouble val = 0.;
  495   guint i;
  496   v->z = 0.;
  497   v->n.x = v->n.y = 0.;
  498   v->n.z = 1.;
  499   for (i = 0; i < inter.n; i++) {
  500     val += inter.w[i]*GFS_VALUE (inter.c[i], gls->v);
  501     v->z += inter.w[i]*GFS_VALUE (inter.c[i], gll->vf->v);
  502     v->n.x -= inter.w[i]*GFS_VALUE (inter.c[i], gll->nx);
  503     v->n.y -= inter.w[i]*GFS_VALUE (inter.c[i], gll->ny);
  504   }
  505   v->p = val;
  506   if (gll->reversed) {
  507     v->n.x = - v->n.x;
  508     v->n.y = - v->n.y;
  509     v->n.z = - 1.;
  510   }
  511 }
  512 
  513 static void gl_linear_color (FttCell * cell, GfsGl * gl)
  514 {
  515   GfsGlScalar * gls = GFS_GL_SCALAR (gl);
  516   if (!GFS_HAS_DATA (cell, gls->v))
  517     return;
  518   gboolean use_scalar = GFS_GL_LINEAR (gl)->use_scalar != NULL;
  519   FttVector p;
  520   Vertex v;
  521   gdouble size = ftt_cell_size (cell)/1.999;
  522   GtsColor c;
  523   FttDirection d[2];
  524 
  525   gl->size++;
  526   ftt_cell_pos (cell, &p);
  527   d[0] = FTT_LEFT; d[1] = FTT_BOTTOM;
  528   new_vertex (cell, d, gl, &v);
  529   if (use_scalar) {
  530     c = color (v.p);
  531     glColor3f (c.r, c.g, c.b);
  532   }
  533   glNormal3d (v.n.x, v.n.y, v.n.z);
  534   glVertex3d (p.x - size, p.y - size, v.z);
  535   d[0] = FTT_RIGHT; d[1] = FTT_BOTTOM;
  536   new_vertex (cell, d, gl, &v);
  537   if (use_scalar) {
  538     c = color (v.p);
  539     glColor3f (c.r, c.g, c.b);
  540   }
  541   glNormal3d (v.n.x, v.n.y, v.n.z);
  542   glVertex3d (p.x + size, p.y - size, v.z);
  543   d[0] = FTT_RIGHT; d[1] = FTT_TOP;
  544   new_vertex (cell, d, gl, &v);
  545   if (use_scalar) {
  546     c = color (v.p);
  547     glColor3f (c.r, c.g, c.b);
  548   }
  549   glNormal3d (v.n.x, v.n.y, v.n.z);
  550   glVertex3d (p.x + size, p.y + size, v.z);
  551   d[0] = FTT_LEFT; d[1] = FTT_TOP;
  552   new_vertex (cell, d, gl, &v);
  553   if (use_scalar) {
  554     c = color (v.p);
  555     glColor3f (c.r, c.g, c.b);
  556   }
  557   glNormal3d (v.n.x, v.n.y, v.n.z);
  558   glVertex3d (p.x - size, p.y + size, v.z);
  559 }
  560 
  561 static void gl_linear_texture (FttCell * cell, GfsGl * gl)
  562 {
  563   GfsGlScalar * gls = GFS_GL_SCALAR (gl);
  564   if (!GFS_HAS_DATA (cell, gls->v))
  565     return;
  566   FttVector p;
  567   Vertex v[4];
  568   gboolean use_scalar = GFS_GL_LINEAR (gl)->use_scalar != NULL;
  569   gdouble size = ftt_cell_size (cell)/1.999;
  570   FttDirection d[2];
  571 
  572   gl->size++;
  573   ftt_cell_pos (cell, &p);
  574 
  575   d[0] = FTT_LEFT; d[1] = FTT_BOTTOM;
  576   new_vertex (cell, d, gl, &v[0]);
  577   d[0] = FTT_RIGHT; d[1] = FTT_BOTTOM;
  578   new_vertex (cell, d, gl, &v[1]);
  579   d[0] = FTT_RIGHT; d[1] = FTT_TOP;
  580   new_vertex (cell, d, gl, &v[2]);
  581   d[0] = FTT_LEFT; d[1] = FTT_TOP;
  582   new_vertex (cell, d, gl, &v[3]);
  583 
  584   glBegin (GL_TRIANGLE_FAN);
  585   if (use_scalar)
  586     glTexCoord1d (param ((v[0].p + v[1].p + v[2].p + v[3].p)/4.));
  587   glNormal3d ((v[0].n.x + v[1].n.x + v[2].n.x + v[3].n.x)/4.,
  588           (v[0].n.y + v[1].n.y + v[2].n.y + v[3].n.y)/4.,
  589           (v[0].n.z + v[1].n.z + v[2].n.z + v[3].n.z)/4.);
  590   glVertex3d (p.x, p.y, (v[0].z + v[1].z + v[2].z + v[3].z)/4.);
  591   if (use_scalar)
  592     glTexCoord1d (param (v[0].p));
  593   glNormal3d (v[0].n.x, v[0].n.y, v[0].n.z);
  594   glVertex3d (p.x - size, p.y - size, v[0].z);
  595   if (use_scalar)
  596     glTexCoord1d (param (v[1].p));
  597   glNormal3d (v[1].n.x, v[1].n.y, v[1].n.z);
  598   glVertex3d (p.x + size, p.y - size, v[1].z);
  599   if (use_scalar)
  600     glTexCoord1d (param (v[2].p));
  601   glNormal3d (v[2].n.x, v[2].n.y, v[2].n.z);
  602   glVertex3d (p.x + size, p.y + size, v[2].z);
  603   if (use_scalar)
  604     glTexCoord1d (param (v[3].p));
  605   glNormal3d (v[3].n.x, v[3].n.y, v[3].n.z);
  606   glVertex3d (p.x - size, p.y + size, v[3].z);
  607   if (use_scalar)
  608     glTexCoord1d (param (v[0].p));
  609   glNormal3d (v[0].n.x, v[0].n.y, v[0].n.z);
  610   glVertex3d (p.x - size, p.y - size, v[0].z);
  611   glEnd ();
  612 }
  613 
  614 static void gl_linear_draw (GfsGl * gl, GfsFrustum * f)
  615 {
  616   gboolean constant = (gfs_function_get_constant_value (GFS_GL_LINEAR (gl)->vf->f) == 0.);
  617   gl->size = 0;
  618   glShadeModel (GL_SMOOTH);
  619   if (constant)
  620     gfs_gl_normal (gl);
  621   if (gfs_gl_vector_format (gl)) {
  622     glBegin (GL_QUADS);
  623     gfs_gl_cell_traverse_visible_plane (gl, f, (FttCellTraverseFunc)
  624                     (constant ? 
  625                      gl_linear_color_constant : 
  626                      gl_linear_color), gl);
  627     glEnd ();
  628   }
  629   else {
  630     if (GFS_GL_LINEAR (gl)->use_scalar) {
  631       glEnable (GL_TEXTURE_1D);
  632       gfs_colormap_texture (GFS_GL_SCALAR (gl)->cmap);
  633       glColor3f (1., 1., 1.);
  634       gfs_gl_cell_traverse_visible_plane (gl, f, (FttCellTraverseFunc)
  635                       (constant ?
  636                        gl_linear_texture_constant :
  637                        gl_linear_texture), gl);
  638       glDisable (GL_TEXTURE_1D);
  639     }
  640     else
  641       gfs_gl_cell_traverse_visible_plane (gl, f, (FttCellTraverseFunc)
  642                       (constant ?
  643                        gl_linear_texture_constant :
  644                        gl_linear_texture), gl);
  645   }
  646 
  647   if (GFS_GL_LINEAR (gl)->use_scalar)
  648     (* GFS_GL_CLASS (GTS_OBJECT (gl)->klass->parent_class)->draw) (gl, f);
  649 }
  650 
  651 /* GfsGlIsoline: Object */
  652 
  653 typedef struct {
  654   FttVector p;
  655   gdouble v;
  656 } VertexIsoline;
  657 
  658 static gdouble inter (VertexIsoline * v1, VertexIsoline * v2, gdouble v)
  659 {
  660   if ((v1->v > v && v2->v <= v) || (v1->v <= v && v2->v > v)) {
  661     gdouble a = (v - v1->v)/(v2->v - v1->v);
  662     glVertex3d (v1->p.x + a*(v2->p.x - v1->p.x),
  663         v1->p.y + a*(v2->p.y - v1->p.y),
  664         v1->p.z + a*(v2->p.z - v1->p.z));
  665 #if DEBUG
  666     fprintf (stderr, "  %g %g %g\n",
  667          v1->p.x + a*(v2->p.x - v1->p.x),
  668          v1->p.y + a*(v2->p.y - v1->p.y),
  669          v1->p.z + a*(v2->p.z - v1->p.z));
  670 #endif
  671     return a;
  672   }
  673   return -1;
  674 }
  675 
  676 static void vertex_isoline (FttCell * cell, FttDirection * d, GfsGl * gl, VertexIsoline * v)
  677 {
  678   ftt_corner_pos (cell, d, &v->p);
  679   if ((v->p.z = gfs_function_get_constant_value (GFS_GL_LINEAR (gl)->vf->f)) != 0.) {
  680     GfsInterpolator inter;
  681     guint i;
  682     gfs_cell_corner_interpolator (cell, d, gl->maxlevel, FALSE, &inter);
  683     v->v = v->p.z = 0.;
  684     for (i = 0; i < inter.n; i++) {
  685       v->v += inter.w[i]*GFS_VALUE (inter.c[i], GFS_GL_SCALAR (gl)->v);
  686       v->p.z += inter.w[i]*GFS_VALUE (inter.c[i], GFS_GL_LINEAR (gl)->vf->v);
  687     }
  688   }
  689   else
  690     v->v = gfs_cell_corner_value (cell, d, GFS_GL_SCALAR (gl)->v, gl->maxlevel);
  691 }
  692 
  693 /* the directions corresponding to the corners */
  694 static FttDirection neighbor[4] = { FTT_BOTTOM, FTT_RIGHT, FTT_TOP, FTT_LEFT };
  695 /* the corners corresponding to the directions */
  696 static FttDirection icorner[4] = { 1, 3, 2, 0 };
  697 
  698 static void set_used (FttCell * cell, gint i, GfsGl * gl)
  699 {
  700   int v = GFS_VALUE (cell, GFS_GL_ISOLINE (gl)->used);
  701   v |= (1 << (i + 1));
  702   GFS_VALUE (cell, GFS_GL_ISOLINE (gl)->used) = v;
  703 }
  704 
  705 static gboolean get_used (FttCell * cell, gint i, GfsGl * gl)
  706 {
  707   return (((int) GFS_VALUE (cell, GFS_GL_ISOLINE (gl)->used)) & (1 << (i + 1))) != 0;
  708 }
  709 
  710 static gboolean get_visible (FttCell * cell, GfsGl * gl)
  711 {
  712   return GFS_VALUE (cell, GFS_GL_ISOLINE (gl)->used) != 0.;
  713 }
  714 
  715 static void follow_isoline (FttCell * cell, gint start, GfsGl * gl, gdouble val)
  716 {
  717   while (cell &&
  718      !GFS_CELL_IS_BOUNDARY (cell) &&
  719      get_visible (cell, gl) && 
  720      GFS_HAS_DATA (cell, GFS_GL_SCALAR (gl)->v)) {
  721     set_used (cell, start, gl);
  722     
  723     gint i1 = (start + 1) % 4;
  724     VertexIsoline v1, v2;
  725     vertex_isoline (cell, corner[i1], gl, &v1);
  726     FttCell * next = NULL;
  727     while (i1 != start && !get_used (cell, i1, gl)) {
  728       gint i2 = (i1 + 1) % 4;
  729       vertex_isoline (cell, corner[i2], gl, &v2);
  730       gdouble a;
  731       if ((a = inter (&v1, &v2, val)) >= 0.) {
  732     gl->size++;
  733     set_used (cell, i1, gl);
  734     FttDirection d = neighbor[i1];
  735     FttCell * n = ftt_cell_neighbor (cell, d);
  736     if (n) {
  737       if (!FTT_CELL_IS_LEAF (n) && !get_visible (n, gl)) {
  738         FttCellChildren child;
  739         ftt_cell_children_direction (n, FTT_OPPOSITE_DIRECTION (d), &child);
  740         gboolean visible0 = (child.c[0] && get_visible (child.c[0], gl));
  741         gboolean visible1 = (child.c[1] && get_visible (child.c[1], gl));
  742         if (visible0) {
  743           if (visible1) {
  744         if (d == FTT_LEFT || d == FTT_BOTTOM)
  745           n = child.c[a > 0.5];
  746         else
  747           n = child.c[a < 0.5];
  748           }
  749           else
  750         n = child.c[0];
  751         }
  752         else if (visible1)
  753           n = child.c[1];
  754         else /* invisible children */
  755           n = NULL;
  756       }
  757     }
  758     next = n;
  759     start = (i1 + 2) % 4;
  760     break;
  761       }
  762       i1 = i2;
  763       v1 = v2;
  764     }
  765     cell = next;
  766   }
  767 }
  768 
  769 static void gl_isoline (FttCell * cell, GfsGl * gl)
  770 {
  771   if (!GFS_HAS_DATA (cell, GFS_GL_SCALAR (gl)->v))
  772     return;
  773   gdouble val = GFS_GL_ISOLINE (gl)->val;
  774 
  775   gint i1 = 0;
  776   VertexIsoline v1, v2;
  777   vertex_isoline (cell, corner[i1], gl, &v1);
  778   do {
  779     gint i2 = (i1 + 1) % 4;
  780     vertex_isoline (cell, corner[i2], gl, &v2);
  781     if (!get_used (cell, i1, gl) && v1.v > val && v2.v <= val) {
  782 #if DEBUG
  783       fprintf (stderr, "# glBegin (GL_LINE_LOOP) %g\n", val);
  784       glColor3f (rand()/(float)RAND_MAX, rand()/(float)RAND_MAX, rand()/(float)RAND_MAX);
  785 #endif
  786 #if 0 /* fixme: this should work but the openGL drivers seem to be buggy... */
  787       FttCell * n = ftt_cell_neighbor (cell, neighbor[i1]);
  788       g_assert (n);
  789       GFS_VALUE (n, GFS_GL_ISOLINE (gl)->used[(i1 + 2) % 4]) = TRUE;
  790       glBegin (GL_LINE_LOOP);
  791 #else
  792       glBegin (GL_LINE_STRIP); /* ... and this seems to work OK */
  793 #endif
  794       inter (&v1, &v2, val);
  795       follow_isoline (cell, i1, gl, val);
  796       glEnd ();
  797 #if DEBUG
  798       fprintf (stderr, "# glEnd ()\n\n");
  799 #endif
  800     }
  801     i1 = i2;
  802     v1 = v2;
  803   } while (i1 != 0);
  804 }
  805 
  806 static gboolean neighbor_is_boundary (FttCell * cell, GfsGl * gl, FttDirection d)
  807 {
  808   if (!cell || GFS_CELL_IS_BOUNDARY (cell))
  809     return TRUE;
  810   gdouble r = ftt_cell_size (cell)*GFS_DIAGONAL;
  811   FttVector p;
  812   ftt_cell_pos (cell, &p);
  813   return (gfs_sphere_in_frustum (&p, r, GFS_GL_ISOLINE (gl)->f) == GTS_OUT);
  814 }
  815 
  816 static void gl_boundary_isoline (FttCell * cell, GfsGl * gl)
  817 {
  818   if (!GFS_HAS_DATA (cell, GFS_GL_SCALAR (gl)->v))
  819     return;
  820   gdouble val = GFS_GL_ISOLINE (gl)->val;
  821 
  822   FttCellNeighbors n;
  823   ftt_cell_neighbors (cell, &n);
  824   FttDirection d;
  825   for (d = 0; d < FTT_NEIGHBORS; d++) {
  826     gint i1 = icorner[d];
  827     if (!get_used (cell, i1, gl) && neighbor_is_boundary (n.c[d], gl, d)) {
  828       VertexIsoline v1, v2;
  829       vertex_isoline (cell, corner[i1], gl, &v1);
  830       gint i2 = (i1 + 1) % 4;
  831       vertex_isoline (cell, corner[i2], gl, &v2);
  832       if (v1.v > val && v2.v <= val) {
  833 #if DEBUG
  834     fprintf (stderr, "# glBegin (GL_LINE_STRIP) %g\n", val);
  835     glColor3f (rand()/(float)RAND_MAX, rand()/(float)RAND_MAX, rand()/(float)RAND_MAX);
  836 #endif
  837     glBegin (GL_LINE_STRIP);
  838     inter (&v1, &v2, val);
  839     follow_isoline (cell, i1, gl, val);
  840     glEnd ();
  841 #if DEBUG
  842     fprintf (stderr, "# glEnd ()\n\n");
  843 #endif
  844       }
  845     }
  846   }
  847 }
  848 
  849 static void set_visible (FttCell * cell, GfsVariable * v)
  850 {
  851   GFS_VALUE (cell, v) = 1.;
  852 }
  853 
  854 static void gl_isoline_draw (GfsGl * gl, GfsFrustum * f)
  855 {
  856   GfsGlIsoline * gli = GFS_GL_ISOLINE (gl);
  857   gl_isoline_update_levels (gl);
  858 
  859   gli->used = gfs_temporary_variable (GFS_DOMAIN (gl->sim));
  860   gfs_domain_cell_traverse (GFS_DOMAIN (gl->sim), FTT_PRE_ORDER, FTT_TRAVERSE_ALL, -1,
  861                 (FttCellTraverseFunc) gfs_cell_reset, gli->used);
  862   gli->f = f;
  863 
  864   gl->size = 0;
  865   glMatrixMode (GL_PROJECTION);
  866   glPushMatrix ();
  867   glTranslatef (0., 0., gl->p->lc);
  868   gfs_gl_normal (gl);
  869   int i;
  870   for (i = 0; i < gli->levels->len; i++) {
  871     gli->val = g_array_index (gli->levels, gdouble, i);
  872     gfs_gl_cell_traverse_visible_iso (gl, f, gli->min, gli->max, gli->val,
  873                       (FttCellTraverseFunc) set_visible, gli->used);
  874     gfs_gl_cell_traverse_visible_iso (gl, f, gli->min, gli->max, gli->val,
  875                       (FttCellTraverseFunc) gl_boundary_isoline, gl);
  876     gfs_gl_cell_traverse_visible_iso (gl, f, gli->min, gli->max, gli->val,
  877                       (FttCellTraverseFunc) gl_isoline, gl);
  878     gfs_gl_cell_traverse_visible_iso (gl, f, gli->min, gli->max, gli->val,
  879                       (FttCellTraverseFunc) gfs_cell_reset, gli->used);
  880   }
  881   glPopMatrix ();
  882                       
  883   gts_object_destroy (GTS_OBJECT (gli->used));
  884 }
  885 
  886 /* GfsGlVOF: Object */
  887 
  888 static void gl_vof (FttCell * cell, GfsGl * gl)
  889 {
  890   FttVector p[2], m;
  891   if (gfs_vof_facet (cell, GFS_VARIABLE_TRACER_VOF (GFS_GL_VOF (gl)->vf->v), p, &m) == 2) {
  892     if (GFS_GL_VOF (gl)->use_scalar) {
  893       GfsGlScalar * gls = GFS_GL_SCALAR (gl);
  894       GtsColor c = gfs_colormap_color (gls->cmap, gls->max > gls->min ?
  895                        (GFS_VALUE (cell, gls->v) - gls->min)/
  896                        (gls->max - gls->min) :
  897                        0.5);
  898       glColor3f (c.r, c.g, c.b);
  899     }
  900     glVertex2d (p[0].x, p[0].y);
  901     glVertex2d (p[1].x, p[1].y);
  902     gl->size++;
  903   }
  904 }
  905 
  906 static gboolean is_vof (FttCell * cell, gpointer data)
  907 {
  908   gdouble f = GFS_VALUE (cell, GFS_GL_VOF (data)->vf->v);
  909 
  910   return !GFS_IS_FULL (f);
  911 }
  912 
  913 static void gl_vof_draw (GfsGl * gl, GfsFrustum * f)
  914 {
  915   if (GFS_IS_VARIABLE_TRACER_VOF (GFS_GL_VOF (gl)->vf->v)) {
  916     gl->size = 0;
  917     glMatrixMode (GL_PROJECTION);
  918     glPushMatrix ();
  919     glTranslatef (0., 0., gl->p->lc);
  920     glBegin (GL_LINES);
  921     gfs_gl_cell_traverse_visible_condition (gl, f, is_vof, gl, (FttCellTraverseFunc) gl_vof, gl);
  922     glEnd ();
  923     glPopMatrix ();
  924   }
  925 }
  926 
  927 static void gl_vof_cut (GfsGl * gl, FttCell * cell, GfsGl2D * plane)
  928 {
  929 }
  930 
  931 /* GfsGlStreamline: Object */
  932 
  933 static void draw_point (GtsPoint * p)
  934 {
  935   glVertex3d (p->x, p->y, p->z);
  936 }
  937 
  938 static void gl_streamline_draw (GfsGlStreamline * s,
  939                 GfsGlStreamlines * gls)
  940 {
  941   glBegin (GL_LINE_STRIP);
  942   g_list_foreach (s->l, (GFunc) draw_point, NULL);
  943   glEnd ();
  944 }