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