1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5 
6 #include <cmath>
7 #include <algorithm>
8 #include "GmshConfig.h"
9 #include "GmshDefines.h"
10 #include "GmshMessage.h"
11 #include "drawContext.h"
12 #include "PView.h"
13 #include "PViewOptions.h"
14 #include "PViewData.h"
15 #include "Plugin.h"
16 #include "Numeric.h"
17 #include "VertexArray.h"
18 #include "Context.h"
19 #include "gl2ps.h"
20 
21 #if defined(HAVE_FLTK)
22 #include <FL/Fl.H>
23 #include <FL/gl.h>
24 #endif
25 
drawArrays(drawContext * ctx,PView * p,VertexArray * va,GLint type,bool useNormalArray)26 static void drawArrays(drawContext *ctx, PView *p, VertexArray *va, GLint type,
27                        bool useNormalArray)
28 {
29   if(!va || !va->getNumVertices()) return;
30 
31   PViewOptions *opt = p->getOptions();
32 
33   if(CTX::instance()->polygonOffset || opt->showElement)
34     glEnable(GL_POLYGON_OFFSET_FILL);
35 
36   if(type == GL_POINTS && opt->pointType > 0) {
37     for(int i = 0; i < va->getNumVertices(); i++) {
38       float *p = va->getVertexArray(3 * i);
39       glColor4ubv((GLubyte *)va->getColorArray(4 * i));
40       double f = 1.;
41       if(opt->pointType > 1) {
42 #if defined(HAVE_VISUDEV)
43         f = *va->getNormalArray(3 * i);
44 #else
45         char *n = va->getNormalArray(3 * i);
46         f = char2float(*n);
47 #endif
48       }
49       if(opt->pointType == 2) {
50         int s = (int)(opt->pointSize * f);
51         if(s) {
52           glPointSize((float)s);
53           gl2psPointSize(
54             (float)(s * CTX::instance()->print.epsPointSizeFactor));
55           glBegin(GL_POINTS);
56           glVertex3d(p[0], p[1], p[2]);
57           glEnd();
58         }
59       }
60       else
61         ctx->drawSphere(opt->pointSize * f, p[0], p[1], p[2], opt->light);
62     }
63   }
64   else if(type == GL_LINES && opt->lineType > 0) {
65     for(int i = 0; i < va->getNumVertices(); i += 2) {
66       float *p0 = va->getVertexArray(3 * i);
67       float *p1 = va->getVertexArray(3 * (i + 1));
68       double x[2] = {p0[0], p1[0]}, y[2] = {p0[1], p1[1]},
69              z[2] = {p0[2], p1[2]};
70       glColor4ubv((GLubyte *)va->getColorArray(4 * i));
71       if(opt->lineType == 2) {
72 #if defined(HAVE_VISUDEV)
73         double v0 = *va->getNormalArray(3 * i);
74         double v1 = *va->getNormalArray(3 * (i + 1));
75 #else
76         char *n0 = va->getNormalArray(3 * i);
77         char *n1 = va->getNormalArray(3 * (i + 1));
78         double v0 = char2float(*n0), v1 = char2float(*n1);
79 #endif
80         ctx->drawTaperedCylinder(opt->lineWidth, v0, v1, 0., 1., x, y, z,
81                                  opt->light);
82       }
83       else if(opt->lineType == 1)
84         ctx->drawCylinder(opt->lineWidth, x, y, z, opt->light);
85       else { // 2D (for now) MNT diagrams for frames
86         float l = std::sqrt((p0[0] - p1[0]) * (p0[0] - p1[0]) +
87                             (p0[1] - p1[1]) * (p0[1] - p1[1]) +
88                             (p0[2] - p1[2]) * (p0[2] - p1[2]));
89 #if defined(HAVE_VISUDEV)
90         double v0 = *va->getNormalArray(3 * i);
91         double v1 = *va->getNormalArray(3 * (i + 1));
92 #else
93         char *n0 = va->getNormalArray(3 * i);
94         char *n1 = va->getNormalArray(3 * (i + 1));
95         double v0 = char2float(*n0), v1 = char2float(*n1);
96 #endif
97         float dir[3] = {(p1[0] - p0[0]) / l, (p1[1] - p0[1]) / l,
98                         (p1[2] - p0[2]) / l};
99         printf("%g %g %g %g %g %g\n", v0, v1, p0[0], p0[1], p1[0], p1[1]);
100         ctx->drawVector(1, 0, p0[0] - dir[1] * v0, p0[1] + dir[0] * v0, 0.0,
101                         p1[0] - dir[1] * v1, p1[1] + dir[0] * v1, 0.0,
102                         opt->light);
103       }
104     }
105   }
106   else {
107 
108     if(type == GL_LINES && opt->useStipple) {
109       glEnable(GL_LINE_STIPPLE);
110       glLineStipple(opt->stipple[0][0], opt->stipple[0][1]);
111       gl2psEnable(GL2PS_LINE_STIPPLE);
112     }
113 
114     glVertexPointer(3, GL_FLOAT, 0, va->getVertexArray());
115     glEnableClientState(GL_VERTEX_ARRAY);
116     if(useNormalArray) {
117       glEnable(GL_LIGHTING);
118       glNormalPointer(NORMAL_GLTYPE, 0, va->getNormalArray());
119       glEnableClientState(GL_NORMAL_ARRAY);
120     }
121     else
122       glDisableClientState(GL_NORMAL_ARRAY);
123     glColorPointer(4, GL_UNSIGNED_BYTE, 0, va->getColorArray());
124     glEnableClientState(GL_COLOR_ARRAY);
125     glDrawArrays(type, 0, va->getNumVertices());
126     glDisableClientState(GL_VERTEX_ARRAY);
127     glDisableClientState(GL_NORMAL_ARRAY);
128     glDisableClientState(GL_COLOR_ARRAY);
129 
130     if(type == GL_LINES && opt->useStipple) {
131       glDisable(GL_LINE_STIPPLE);
132       gl2psDisable(GL2PS_LINE_STIPPLE);
133     }
134 
135   }
136 
137   glDisable(GL_POLYGON_OFFSET_FILL);
138   glDisable(GL_LIGHTING);
139 }
140 
drawEllipseArray(drawContext * ctx,PView * p,VertexArray * va)141 static void drawEllipseArray(drawContext *ctx, PView *p, VertexArray *va)
142 {
143   if(!va || va->getNumVerticesPerElement() != 4) return;
144 
145   PViewOptions *opt = p->getOptions();
146 
147   for(int i = 0; i < va->getNumVertices(); i += 4) {
148     float *s = va->getVertexArray(3 * i);
149     float vv[3][3];
150     double lmax = opt->tmpMax;
151     double scale = (opt->arrowSizeMax - opt->arrowSizeMin) *
152                    ctx->pixel_equiv_x / ctx->s[0] / 2;
153     double lmin = opt->arrowSizeMin * ctx->pixel_equiv_x / ctx->s[0] / 2;
154     for(int j = 0; j < 3; j++) {
155       float *v = va->getVertexArray(3 * (i + j + 1));
156       double l = std::sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
157       double l2 = std::min(1., l / lmax);
158       for(int k = 0; k < 3; k++) { vv[j][k] = v[k] / l * (scale * l2 + lmin); }
159     }
160     glColor4ubv((GLubyte *)va->getColorArray(4 * i));
161     if(opt->tensorType == PViewOptions::Ellipsoid)
162       ctx->drawEllipsoid(s[0], s[1], s[2], vv[0], vv[1], vv[2], opt->light);
163     else
164       ctx->drawEllipse(s[0], s[1], s[2], vv[0], vv[1], opt->light);
165   }
166 }
167 
drawVectorArray(drawContext * ctx,PView * p,VertexArray * va)168 static void drawVectorArray(drawContext *ctx, PView *p, VertexArray *va)
169 {
170   if(!va || va->getNumVerticesPerElement() != 2) return;
171 
172   PViewOptions *opt = p->getOptions();
173 
174   for(int i = 0; i < va->getNumVertices(); i += 2) {
175     float *s = va->getVertexArray(3 * i);
176     float *v = va->getVertexArray(3 * (i + 1));
177     glColor4ubv((GLubyte *)va->getColorArray(4 * i));
178     double vv[3] = {v[0], v[1], v[2]};
179     double l = sqrt(vv[0] * vv[0] + vv[1] * vv[1] + vv[2] * vv[2]);
180     double lmax = opt->tmpMax;
181     if((l || opt->vectorType == 6) && lmax) {
182       double scale = (opt->arrowSizeMax - opt->arrowSizeMin) / lmax;
183       // log scaling
184       if(opt->scaleType == PViewOptions::Logarithmic && opt->tmpMin > 0 &&
185          opt->tmpMax > opt->tmpMin && l != opt->tmpMin) {
186         scale = (opt->arrowSizeMax - opt->arrowSizeMin) / l *
187                 log10(l / opt->tmpMin) / log10(opt->tmpMax / opt->tmpMin);
188       }
189       if(opt->arrowSizeMin && l) scale += opt->arrowSizeMin / l;
190       double px = scale * v[0];
191       double py = scale * v[1];
192       double pz = scale * v[2];
193       // only draw vectors larger than 1 pixel on screen, except when
194       // drawing "comet" glyphs
195       if(opt->vectorType == 6 || fabs(px) > 1. || fabs(py) > 1. ||
196          fabs(pz) > 1.) {
197         double d = ctx->pixel_equiv_x / ctx->s[0];
198         double dx = px * d, dy = py * d, dz = pz * d;
199         double x = s[0], y = s[1], z = s[2];
200         if(opt->centerGlyphs == 2) {
201           x -= dx;
202           y -= dy;
203           z -= dz;
204         }
205         else if(opt->centerGlyphs == 1) {
206           x -= 0.5 * dx;
207           y -= 0.5 * dy;
208           z -= 0.5 * dz;
209         }
210         ctx->drawVector(opt->vectorType,
211                         opt->intervalsType != PViewOptions::Iso, x, y, z, dx,
212                         dy, dz, opt->light);
213       }
214     }
215   }
216 }
217 
stringValue(int numComp,double d[9],double norm,const char * format)218 static std::string stringValue(int numComp, double d[9], double norm,
219                                const char *format)
220 {
221   char label[100];
222   if(numComp == 1)
223     sprintf(label, format, d[0]);
224   else if(numComp == 3) {
225     char str[3][32];
226     sprintf(str[0], format, d[0]);
227     sprintf(str[1], format, d[1]);
228     sprintf(str[2], format, d[2]);
229     sprintf(label, "(%s,%s,%s)", str[0], str[1], str[2]);
230   }
231   else if(numComp == 9)
232     sprintf(label, format, norm);
233   return std::string(label);
234 }
235 
drawNumberGlyphs(drawContext * ctx,PView * p,int numNodes,int numComp,double ** xyz,double ** val)236 static void drawNumberGlyphs(drawContext *ctx, PView *p, int numNodes,
237                              int numComp, double **xyz, double **val)
238 {
239   PViewOptions *opt = p->getOptions();
240   double d[9] = {0., 0., 0., 0., 0., 0., 0., 0., 0.};
241 
242   double vmin = opt->tmpMin, vmax = opt->tmpMax;
243 
244   if(opt->glyphLocation == PViewOptions::COG) {
245     SPoint3 pc(0., 0., 0.);
246     for(int i = 0; i < numNodes; i++) {
247       pc += SPoint3(xyz[i][0], xyz[i][1], xyz[i][2]);
248       for(int j = 0; j < numComp; j++) d[j] += val[i][j];
249     }
250     pc /= (double)numNodes;
251     for(int j = 0; j < numComp; j++) d[j] /= (double)numNodes;
252     double v = ComputeScalarRep(numComp, d);
253     if(v >= vmin && v <= vmax) {
254       unsigned int col = opt->getColor(v, vmin, vmax, false, opt->nbIso);
255       glColor4ubv((GLubyte *)&col);
256       if(opt->centerGlyphs == 2)
257         ctx->drawStringRight(stringValue(numComp, d, v, opt->format.c_str()),
258                              pc.x(), pc.y(), pc.z());
259       else if(opt->centerGlyphs == 1)
260         ctx->drawStringCenter(stringValue(numComp, d, v, opt->format.c_str()),
261                               pc.x(), pc.y(), pc.z());
262       else
263         ctx->drawString(stringValue(numComp, d, v, opt->format.c_str()), pc.x(),
264                         pc.y(), pc.z());
265     }
266   }
267   else if(opt->glyphLocation == PViewOptions::Vertex) {
268     for(int i = 0; i < numNodes; i++) {
269       double v = ComputeScalarRep(numComp, val[i]);
270       if(v >= vmin && v <= vmax) {
271         unsigned int col = opt->getColor(v, vmin, vmax, false, opt->nbIso);
272         glColor4ubv((GLubyte *)&col);
273         if(opt->centerGlyphs == 2)
274           ctx->drawStringRight(
275             stringValue(numComp, val[i], v, opt->format.c_str()), xyz[i][0],
276             xyz[i][1], xyz[i][2]);
277         else if(opt->centerGlyphs == 1)
278           ctx->drawStringCenter(
279             stringValue(numComp, val[i], v, opt->format.c_str()), xyz[i][0],
280             xyz[i][1], xyz[i][2]);
281         else
282           ctx->drawString(stringValue(numComp, val[i], v, opt->format.c_str()),
283                           xyz[i][0], xyz[i][1], xyz[i][2]);
284       }
285     }
286   }
287 }
288 
drawNormalVectorGlyphs(drawContext * ctx,PView * p,int numNodes,double ** xyz,double ** val)289 static void drawNormalVectorGlyphs(drawContext *ctx, PView *p, int numNodes,
290                                    double **xyz, double **val)
291 {
292   PViewOptions *opt = p->getOptions();
293 
294   SPoint3 pc(0., 0., 0.);
295   for(int i = 0; i < numNodes; i++)
296     pc += SPoint3(xyz[i][0], xyz[i][1], xyz[i][2]);
297   pc /= (double)numNodes;
298 
299   SVector3 t1(xyz[1][0] - xyz[0][0], xyz[1][1] - xyz[0][1],
300               xyz[1][2] - xyz[0][2]);
301   SVector3 t2(xyz[2][0] - xyz[0][0], xyz[2][1] - xyz[0][1],
302               xyz[2][2] - xyz[0][2]);
303   SVector3 n = crossprod(t1, t2);
304   n.normalize();
305 
306   for(int i = 0; i < 3; i++)
307     n[i] *= opt->normals * ctx->pixel_equiv_x / ctx->s[i];
308   glColor4ubv((GLubyte *)&opt->color.normals);
309   ctx->drawVector(CTX::instance()->vectorType, 0, pc[0], pc[1], pc[2], n[0],
310                   n[1], n[2], opt->light);
311 }
312 
drawTangentVectorGlyphs(drawContext * ctx,PView * p,int numNodes,double ** xyz,double ** val)313 static void drawTangentVectorGlyphs(drawContext *ctx, PView *p, int numNodes,
314                                     double **xyz, double **val)
315 {
316   PViewOptions *opt = p->getOptions();
317 
318   SPoint3 p0(xyz[0][0], xyz[0][1], xyz[0][2]);
319   SPoint3 p1(xyz[1][0], xyz[1][1], xyz[1][2]);
320   SVector3 pc = 0.5 * (p0 + p1);
321   SVector3 t(p0, p1);
322   t.normalize();
323   for(int i = 0; i < 3; i++)
324     t[i] *= opt->tangents * ctx->pixel_equiv_x / ctx->s[i];
325   glColor4ubv((GLubyte *)&opt->color.tangents);
326   ctx->drawVector(CTX::instance()->vectorType, 0, pc[0], pc[1], pc[2], t[0],
327                   t[1], t[2], opt->light);
328 }
329 
drawGlyphs(drawContext * ctx,PView * p)330 static void drawGlyphs(drawContext *ctx, PView *p)
331 {
332   static int numNodesError = 0;
333 
334   // use adaptive data if available
335   PViewData *data = p->getData(true);
336   PViewOptions *opt = p->getOptions();
337 
338   if(!opt->normals && !opt->tangents &&
339      opt->intervalsType != PViewOptions::Numeric)
340     return;
341 
342   Msg::Debug("drawing extra glyphs (this is slow...)");
343 
344   // speedup drawing of textured fonts on cocoa mac version
345 #if defined(HAVE_FLTK) && defined(__APPLE__)
346   if(opt->intervalsType == PViewOptions::Numeric) {
347     int numStrings = 0;
348     for(int ent = 0; ent < data->getNumEntities(opt->timeStep); ent++)
349       numStrings += data->getNumElements(opt->timeStep, ent);
350     if(gl_texture_pile_height() < numStrings)
351       gl_texture_pile_height(numStrings);
352   }
353 #endif
354 
355   // double xyz[PVIEW_NMAX][3], val[PVIEW_NMAX][9];
356   int NMAX = PVIEW_NMAX;
357   double **xyz = new double *[NMAX];
358   double **val = new double *[NMAX];
359   for(int i = 0; i < NMAX; i++) {
360     xyz[i] = new double[3];
361     val[i] = new double[9];
362   }
363   for(int ent = 0; ent < data->getNumEntities(opt->timeStep); ent++) {
364     if(data->skipEntity(opt->timeStep, ent)) continue;
365     for(int i = 0; i < data->getNumElements(opt->timeStep, ent); i++) {
366       if(data->skipElement(opt->timeStep, ent, i, true, opt->sampling))
367         continue;
368       int type = data->getType(opt->timeStep, ent, i);
369       if(opt->skipElement(type)) continue;
370       int dim = data->getDimension(opt->timeStep, ent, i);
371       int numComp = data->getNumComponents(opt->timeStep, ent, i);
372       int numNodes = data->getNumNodes(opt->timeStep, ent, i);
373       if(numNodes > NMAX) {
374         if(type == TYPE_POLYG || type == TYPE_POLYH) {
375           for(int j = 0; j < NMAX; j++) {
376             delete[] xyz[i];
377             delete[] val[i];
378           }
379           delete[] xyz;
380           delete[] val;
381           NMAX = numNodes;
382           xyz = new double *[NMAX];
383           val = new double *[NMAX];
384           for(int j = 0; j < NMAX; j++) {
385             xyz[j] = new double[3];
386             val[j] = new double[9];
387           }
388         }
389         else {
390           if(numNodesError != numNodes) {
391             numNodesError = numNodes;
392             Msg::Warning(
393               "Fields with %d nodes per element cannot be displayed: "
394               "either force the field type or select 'Adapt visualization "
395               "grid' if the field is high-order",
396               numNodes);
397           }
398           continue;
399         }
400       }
401       for(int j = 0; j < numNodes; j++) {
402         data->getNode(opt->timeStep, ent, i, j, xyz[j][0], xyz[j][1],
403                       xyz[j][2]);
404         if(opt->forceNumComponents) {
405           for(int k = 0; k < opt->forceNumComponents; k++) {
406             int comp = opt->componentMap[k];
407             if(comp >= 0 && comp < numComp)
408               data->getValue(opt->timeStep, ent, i, j, comp, val[j][k]);
409             else
410               val[j][k] = 0.;
411           }
412         }
413         else
414           for(int k = 0; k < numComp; k++)
415             data->getValue(opt->timeStep, ent, i, j, k, val[j][k]);
416       }
417       if(opt->forceNumComponents) numComp = opt->forceNumComponents;
418       changeCoordinates(p, ent, i, numNodes, type, numComp, xyz, val);
419       if(!isElementVisible(opt, dim, numNodes, xyz)) continue;
420       if(opt->intervalsType == PViewOptions::Numeric)
421         drawNumberGlyphs(ctx, p, numNodes, numComp, xyz, val);
422       if(dim == 2 && opt->normals)
423         drawNormalVectorGlyphs(ctx, p, numNodes, xyz, val);
424       else if(dim == 1 && opt->tangents)
425         drawTangentVectorGlyphs(ctx, p, numNodes, xyz, val);
426     }
427   }
428   for(int j = 0; j < NMAX; j++) {
429     delete[] xyz[j];
430     delete[] val[j];
431   }
432   delete[] xyz;
433   delete[] val;
434 }
435 
eyeChanged(drawContext * ctx,PView * p)436 static bool eyeChanged(drawContext *ctx, PView *p)
437 {
438   double zeye = 100 * CTX::instance()->lc;
439   SPoint3 tmp(ctx->rot[2] * zeye, ctx->rot[6] * zeye, ctx->rot[10] * zeye);
440   if(tmp.distance(p->getEye()) > 1.e-3) {
441     p->setEye(tmp);
442     return true;
443   }
444   return false;
445 }
446 
447 class drawPView {
448 private:
449   drawContext *_ctx;
450 
451 public:
drawPView(drawContext * ctx)452   drawPView(drawContext *ctx) : _ctx(ctx) {}
operator ()(PView * p)453   void operator()(PView *p)
454   {
455     // use adaptive data if available
456     PViewData *data = p->getData(true);
457     PViewOptions *opt = p->getOptions();
458 
459     if(data->getDirty() || !data->getNumTimeSteps()) return;
460     if(!opt->visible || opt->type != PViewOptions::Plot3D) return;
461     if(!_ctx->isVisible(p)) return;
462 
463     if(_ctx->render_mode == drawContext::GMSH_SELECT) {
464       glPushName(5);
465       glPushName(p->getIndex());
466     }
467 
468     glPointSize((float)opt->pointSize);
469     gl2psPointSize(
470       (float)(opt->pointSize * CTX::instance()->print.epsPointSizeFactor));
471 
472     glLineWidth((float)opt->lineWidth);
473     gl2psLineWidth(
474       (float)(opt->lineWidth * CTX::instance()->print.epsLineWidthFactor));
475 
476     if(opt->axes && opt->type == PViewOptions::Plot3D) {
477       glColor4ubv((GLubyte *)&opt->color.axes);
478       glLineWidth((float)CTX::instance()->lineWidth);
479       gl2psLineWidth((float)(CTX::instance()->lineWidth *
480                              CTX::instance()->print.epsLineWidthFactor));
481       if(!opt->axesAutoPosition)
482         _ctx->drawAxes(opt->axes, opt->axesTics, opt->axesFormat,
483                        opt->axesLabel, opt->axesPosition, opt->axesMikado,
484                        opt->axesPosition);
485       else if(!opt->tmpBBox.empty())
486         _ctx->drawAxes(opt->axes, opt->axesTics, opt->axesFormat,
487                        opt->axesLabel, opt->tmpBBox, opt->axesMikado,
488                        opt->tmpBBox);
489     }
490 
491     if(!CTX::instance()->clipWholeElements) {
492       for(int i = 0; i < 6; i++)
493         if(opt->clip & (1 << i))
494           glEnable((GLenum)(GL_CLIP_PLANE0 + i));
495         else
496           glDisable((GLenum)(GL_CLIP_PLANE0 + i));
497     }
498 
499     if(CTX::instance()->alpha && ColorTable_IsAlpha(&opt->colorTable)) {
500       if(opt->fakeTransparency) {
501         // simple additive blending "a la xpost":
502         glBlendFunc(GL_SRC_ALPHA, GL_ONE); // glBlendEquation(GL_FUNC_ADD);
503         // maximum intensity projection "a la volsuite":
504         // glBlendFunc(GL_ONE, GL_ONE); // glBlendEquation(GL_MAX);
505         glEnable(GL_BLEND);
506         glDisable(GL_DEPTH_TEST);
507       }
508       else {
509         // real translucent blending (requires back-to-front traversal)
510         glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
511         // glBlendEquation(GL_FUNC_ADD);
512         glEnable(GL_BLEND);
513         if(p->va_triangles && p->va_triangles->getNumVertices() &&
514            eyeChanged(_ctx, p)) {
515           Msg::Debug("Sorting View[%d] for transparency", p->getIndex());
516           p->va_triangles->sort(p->getEye().x(), p->getEye().y(),
517                                 p->getEye().z());
518         }
519       }
520     }
521 
522     if(opt->rangeType == PViewOptions::Custom) {
523       opt->tmpMin = opt->customMin;
524       opt->tmpMax = opt->customMax;
525     }
526     else if(opt->rangeType == PViewOptions::PerTimeStep) {
527       opt->tmpMin = data->getMin(opt->timeStep);
528       opt->tmpMax = data->getMax(opt->timeStep);
529     }
530     else {
531       // FIXME: this is not perfect for multi-step adaptive views, as
532       // we don't have the correct min/max info for the other steps
533       opt->tmpMin = data->getMin();
534       opt->tmpMax = data->getMax();
535     }
536 
537     // draw all the vertex arrays
538     glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
539 
540     drawArrays(_ctx, p, p->va_points, GL_POINTS, false);
541     drawArrays(_ctx, p, p->va_lines, GL_LINES, opt->light && opt->lightLines);
542 
543     if(opt->lightTwoSide) glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
544 
545     drawArrays(_ctx, p, p->va_triangles, GL_TRIANGLES, opt->light);
546 
547     // draw the "pseudo" vertex arrays for vectors
548     drawVectorArray(_ctx, p, p->va_vectors);
549     drawEllipseArray(_ctx, p, p->va_ellipses);
550 
551     // to avoid looping over elements (and to enable drawing glyphs
552     // for remote views) we should also store these glyphs in "pseudo"
553     // vertex arrays
554     drawGlyphs(_ctx, p);
555 
556     // draw the 3D strings
557     if(opt->drawStrings) {
558       glColor4ubv((GLubyte *)&opt->color.text3d);
559       for(int i = 0; i < data->getNumStrings3D(); i++) {
560         double x, y, z, style;
561         std::string str;
562         data->getString3D(i, opt->timeStep, str, x, y, z, style);
563         _ctx->drawString(str, x, y, z, style);
564       }
565     }
566 
567     if(CTX::instance()->alpha) {
568       glDisable(GL_BLEND);
569       glEnable(GL_DEPTH_TEST);
570     }
571 
572     for(int i = 0; i < 6; i++) glDisable((GLenum)(GL_CLIP_PLANE0 + i));
573 
574     if(_ctx->render_mode == drawContext::GMSH_SELECT) {
575       glPopName();
576       glPopName();
577     }
578   }
579 };
580 
581 class drawPViewBoundingBox {
582 private:
583   drawContext *_ctx;
584 
585 public:
drawPViewBoundingBox(drawContext * ctx)586   drawPViewBoundingBox(drawContext *ctx) : _ctx(ctx) {}
operator ()(PView * p)587   void operator()(PView *p)
588   {
589     PViewData *data = p->getData();
590     PViewOptions *opt = p->getOptions();
591 
592     if(!opt->visible || opt->type != PViewOptions::Plot3D) return;
593 
594     SBoundingBox3d bb = data->getBoundingBox(opt->timeStep);
595     if(bb.empty()) return;
596 
597     glColor4ubv((GLubyte *)&CTX::instance()->color.fg);
598     glLineWidth((float)CTX::instance()->lineWidth);
599     gl2psLineWidth((float)(CTX::instance()->lineWidth *
600                            CTX::instance()->print.epsLineWidthFactor));
601 
602     _ctx->drawBox(bb.min().x(), bb.min().y(), bb.min().z(), bb.max().x(),
603                   bb.max().y(), bb.max().z());
604     glColor3d(1., 0., 0.);
605     for(int i = 0; i < 6; i++)
606       if(opt->clip & (1 << i))
607         _ctx->drawPlaneInBoundingBox(
608           bb.min().x(), bb.min().y(), bb.min().z(), bb.max().x(), bb.max().y(),
609           bb.max().z(), CTX::instance()->clipPlane[i][0],
610           CTX::instance()->clipPlane[i][1], CTX::instance()->clipPlane[i][2],
611           CTX::instance()->clipPlane[i][3]);
612   }
613 };
614 
drawPost()615 void drawContext::drawPost()
616 {
617   // draw any plugin-specific stuff
618   if(GMSH_Plugin::draw) (*GMSH_Plugin::draw)(this);
619 
620   if(PView::list.empty()) return;
621 
622   if(CTX::instance()->drawBBox || !CTX::instance()->post.draw)
623     std::for_each(PView::list.begin(), PView::list.end(),
624                   drawPViewBoundingBox(this));
625 
626   if(!CTX::instance()->post.draw) return;
627 
628   for(std::size_t i = 0; i < PView::list.size(); i++) {
629     bool changed = PView::list[i]->fillVertexArrays();
630     if(changed) Msg::Debug("post-pro vertex arrays have changed");
631 #if defined(HAVE_FLTK) && defined(__APPLE__)
632     // FIXME: resetting texture pile fixes bug with recent MacOS versions
633     if(changed) gl_texture_pile_height(gl_texture_pile_height());
634 #endif
635   }
636 
637   std::for_each(PView::list.begin(), PView::list.end(), drawPView(this));
638 }
639