1 #include "GLView.h"
2
3 #include "stdio.h"
4 #include "colormap.h"
5 #include "rendersettings.h"
6 #include "printutils.h"
7 #include "renderer.h"
8 #include "degree_trig.h"
9 #include <cmath>
10 #include "boost-utils.h"
11 #ifdef _WIN32
12 #include <GL/wglew.h>
13 #elif !defined(__APPLE__)
14 #include <GL/glxew.h>
15 #endif
16
17 #ifdef ENABLE_OPENCSG
18 #include <opencsg.h>
19 #endif
20
GLView()21 GLView::GLView()
22 {
23 aspectratio = 1;
24 showedges = false;
25 showfaces = true;
26 showaxes = false;
27 showcrosshairs = false;
28 showscale = false;
29 renderer = nullptr;
30 colorscheme = &ColorMap::inst()->defaultColorScheme();
31 cam = Camera();
32 far_far_away = RenderSettings::inst()->far_gl_clip_limit;
33 #ifdef ENABLE_OPENCSG
34 is_opencsg_capable = false;
35 has_shaders = false;
36 opencsg_support = true;
37 static int sId = 0;
38 this->opencsg_id = sId++;
39 #endif
40 }
41
setRenderer(Renderer * r)42 void GLView::setRenderer(Renderer* r)
43 {
44 renderer = r;
45 }
46
47 /* update the color schemes of the Renderer attached to this GLView
48 to match the colorscheme of this GLView.*/
updateColorScheme()49 void GLView::updateColorScheme()
50 {
51 if (this->renderer) this->renderer->setColorScheme(*this->colorscheme);
52 }
53
54 /* change this GLView's colorscheme to the one given, and update the
55 Renderer attached to this GLView as well. */
setColorScheme(const ColorScheme & cs)56 void GLView::setColorScheme(const ColorScheme &cs)
57 {
58 this->colorscheme = &cs;
59 this->updateColorScheme();
60 }
61
setColorScheme(const std::string & cs)62 void GLView::setColorScheme(const std::string &cs)
63 {
64 const auto colorscheme = ColorMap::inst()->findColorScheme(cs);
65 if (colorscheme) {
66 setColorScheme(*colorscheme);
67 }
68 else {
69 LOG(message_group::UI_Warning,Location::NONE,"","GLView: unknown colorscheme %1$s",cs);
70 }
71 }
72
resizeGL(int w,int h)73 void GLView::resizeGL(int w, int h)
74 {
75 cam.pixel_width = w;
76 cam.pixel_height = h;
77 glViewport(0, 0, w, h);
78 aspectratio = 1.0*w/h;
79 }
80
setCamera(const Camera & cam)81 void GLView::setCamera(const Camera &cam)
82 {
83 this->cam = cam;
84 }
85
setupCamera() const86 void GLView::setupCamera() const
87 {
88 glMatrixMode(GL_PROJECTION);
89 glLoadIdentity();
90 auto dist = cam.zoomValue();
91 switch (this->cam.projection) {
92 case Camera::ProjectionType::PERSPECTIVE: {
93 gluPerspective(cam.fov, aspectratio, 0.1 * dist, 100 * dist);
94 break;
95 }
96 default:
97 case Camera::ProjectionType::ORTHOGONAL: {
98 auto height = dist * tan_degrees(cam.fov / 2);
99 glOrtho(-height * aspectratio, height * aspectratio,
100 -height, height,
101 -100 * dist, +100 * dist);
102 break;
103 }
104 }
105 glMatrixMode(GL_MODELVIEW);
106 glLoadIdentity();
107 gluLookAt(0.0, -dist, 0.0, // eye
108 0.0, 0.0, 0.0, // center
109 0.0, 0.0, 1.0); // up
110
111 glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
112 glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
113 glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
114 }
115
paintGL()116 void GLView::paintGL()
117 {
118 glDisable(GL_LIGHTING);
119 auto bgcol = ColorMap::getColor(*this->colorscheme, RenderColor::BACKGROUND_COLOR);
120 auto axescolor = ColorMap::getColor(*this->colorscheme, RenderColor::AXES_COLOR);
121 auto crosshaircol = ColorMap::getColor(*this->colorscheme, RenderColor::CROSSHAIR_COLOR);
122 glClearColor(bgcol[0], bgcol[1], bgcol[2], 1.0);
123 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
124
125 setupCamera();
126 // The crosshair should be fixed at the center of the viewport...
127 if (showcrosshairs) GLView::showCrosshairs(crosshaircol);
128 glTranslated(cam.object_trans.x(), cam.object_trans.y(), cam.object_trans.z());
129 // ...the axis lines need to follow the object translation.
130 if (showaxes) GLView::showAxes(axescolor);
131 // mark the scale along the axis lines
132 if (showaxes && showscale) GLView::showScalemarkers(axescolor);
133
134 glEnable(GL_LIGHTING);
135 glDepthFunc(GL_LESS);
136 glCullFace(GL_BACK);
137 glDisable(GL_CULL_FACE);
138 glLineWidth(2);
139 glColor3d(1.0, 0.0, 0.0);
140
141 if (this->renderer) {
142 #if defined(ENABLE_OPENCSG)
143 // FIXME: This belongs in the OpenCSG renderer, but it doesn't know about this ID yet
144 OpenCSG::setContext(this->opencsg_id);
145 #endif
146 this->renderer->draw(showfaces, showedges);
147 }
148
149 glDisable(GL_LIGHTING);
150 if (showaxes) GLView::showSmallaxes(axescolor);
151 }
152
153 #ifdef ENABLE_OPENCSG
154
glErrorCheck()155 void glErrorCheck() {
156 GLenum err = glGetError();
157 if (err != GL_NO_ERROR) {
158 fprintf(stderr, "OpenGL Error: %s\n", gluErrorString(err));
159 }
160 }
161
glCompileCheck(GLuint shader)162 void glCompileCheck(GLuint shader) {
163 GLint status;
164 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
165 if (status == GL_FALSE) {
166 int loglen;
167 char logbuffer[1000];
168 glGetShaderInfoLog(shader, sizeof(logbuffer), &loglen, logbuffer);
169 PRINTDB("OpenGL Shader Program Compile Error:\n%s", logbuffer);
170 }
171 }
172
enable_opencsg_shaders()173 void GLView::enable_opencsg_shaders()
174 {
175 const char *openscad_disable_gl20_env = getenv("OPENSCAD_DISABLE_GL20");
176 if (openscad_disable_gl20_env && !strcmp(openscad_disable_gl20_env, "0")) {
177 openscad_disable_gl20_env = nullptr;
178 }
179
180 // All OpenGL 2 contexts are OpenCSG capable
181 if (GLEW_VERSION_2_0) {
182 if (!openscad_disable_gl20_env) {
183 this->is_opencsg_capable = true;
184 this->has_shaders = true;
185 }
186 }
187
188 // If OpenGL < 2, check for extensions
189 else {
190 if (GLEW_ARB_framebuffer_object) this->is_opencsg_capable = true;
191 else if (GLEW_EXT_framebuffer_object && GLEW_EXT_packed_depth_stencil) {
192 this->is_opencsg_capable = true;
193 }
194 #ifdef _WIN32
195 else if (WGLEW_ARB_pbuffer && WGLEW_ARB_pixel_format) this->is_opencsg_capable = true;
196 #elif !defined(__APPLE__)
197 else if (GLXEW_SGIX_pbuffer && GLXEW_SGIX_fbconfig) this->is_opencsg_capable = true;
198 #endif
199 }
200
201 if (!GLEW_VERSION_2_0 || !this->is_opencsg_capable) {
202 display_opencsg_warning();
203 }
204
205 if (opencsg_support && this->has_shaders) {
206
207 const char *vs_source = R"VS_PROG(
208 #version 110
209
210 uniform vec4 color1; // face color
211 uniform vec4 color2; // edge color
212 attribute vec3 barycentric; // barycentric form of vertex coord
213 // either [1,0,0], [0,1,0] or [0,0,1] under normal circumstances (no edges disabled)
214 varying vec3 vBC; // varying barycentric coords
215 varying float shading; // multiplied by color1. color2 is without lighting
216
217 void main(void) {
218 gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
219 vBC = barycentric;
220 vec3 normal, lightDir;
221 normal = normalize(gl_NormalMatrix * gl_Normal);
222 lightDir = normalize(vec3(gl_LightSource[0].position));
223 shading = 0.2 + abs(dot(normal, lightDir));
224 }
225 )VS_PROG";
226
227 const char *fs_source = R"FS_PROG(
228 #version 110
229
230 uniform vec4 color1, color2;
231 varying vec3 vBC;
232 varying float shading;
233
234 vec3 smoothstep3f(vec3 edge0, vec3 edge1, vec3 x) {
235 vec3 t;
236 t = clamp((x - edge0) / (edge1 - edge0), 0.0, 1.0);
237 return t * t * (3.0 - 2.0 * t);
238 }
239
240 float edgeFactor() {
241 const float th = 1.414; // total thickness of half-edge (per triangle) including fade, (must be >= fade)
242 const float fade = 1.414; // thickness of fade (antialiasing) in screen pixels
243 vec3 d = fwidth(vBC);
244 vec3 a3 = smoothstep((th-fade)*d, th*d, vBC);
245 return min(min(a3.x, a3.y), a3.z);
246 }
247
248 void main(void) {
249 gl_FragColor = mix(color2, vec4(color1.rgb * shading, color1.a), edgeFactor());
250 }
251 )FS_PROG";
252
253 auto vs = glCreateShader(GL_VERTEX_SHADER);
254 glShaderSource(vs, 1, (const GLchar**)&vs_source, nullptr);
255 glCompileShader(vs);
256 glCompileCheck(vs);
257 glErrorCheck();
258
259 auto fs = glCreateShader(GL_FRAGMENT_SHADER);
260 glShaderSource(fs, 1, (const GLchar**)&fs_source, nullptr);
261 glCompileShader(fs);
262 glCompileCheck(fs);
263 glErrorCheck();
264
265 auto edgeshader_prog = glCreateProgram();
266 glAttachShader(edgeshader_prog, vs);
267 glAttachShader(edgeshader_prog, fs);
268 glLinkProgram(edgeshader_prog);
269 glErrorCheck();
270
271 shaderinfo.progid = edgeshader_prog; // 0
272 shaderinfo.type = GLView::shaderinfo_t::CSG_RENDERING;
273 shaderinfo.data.csg_rendering.color_area = glGetUniformLocation(edgeshader_prog, "color1"); // 1
274 glErrorCheck();
275 shaderinfo.data.csg_rendering.color_edge = glGetUniformLocation(edgeshader_prog, "color2"); // 2
276 glErrorCheck();
277 shaderinfo.data.csg_rendering.barycentric = glGetAttribLocation(edgeshader_prog, "barycentric");
278 glErrorCheck();
279
280 GLint status;
281 glGetProgramiv(edgeshader_prog, GL_LINK_STATUS, &status);
282 if (status == GL_FALSE) {
283 int loglen;
284 char logbuffer[1000];
285 glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer);
286 fprintf(stderr, "OpenGL Program Linker Error:\n%.*s", loglen, logbuffer);
287 } else {
288 int loglen;
289 char logbuffer[1000];
290 glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer);
291 if (loglen > 0) {
292 fprintf(stderr, "OpenGL Program Link OK:\n%.*s", loglen, logbuffer);
293 }
294 glValidateProgram(edgeshader_prog);
295 glGetProgramInfoLog(edgeshader_prog, sizeof(logbuffer), &loglen, logbuffer);
296 if (loglen > 0) {
297 fprintf(stderr, "OpenGL Program Validation results:\n%.*s", loglen, logbuffer);
298 }
299 }
300 }
301 }
302 #endif
303
304
305 #ifdef DEBUG
306 // Requires OpenGL 4.3+
307 /*
308 void GLAPIENTRY MessageCallback(GLenum source, GLenum type, GLuint id, GLenum severity,
309 GLsizei length, const GLchar* message, const void* userParam)
310 {
311 fprintf(stderr, "GL CALLBACK: %s type = 0x%X, severity = 0x%X, message = %s\n",
312 (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ),
313 type, severity, message);
314 }
315 //*/
316 #endif
317
initializeGL()318 void GLView::initializeGL()
319 {
320 #ifdef DEBUG
321 /*
322 // Requires OpenGL 4.3+
323 glEnable ( GL_DEBUG_OUTPUT );
324 glDebugMessageCallback( MessageCallback, 0 );
325 //*/
326 #endif
327
328 glEnable(GL_DEPTH_TEST);
329 glDepthRange(-far_far_away, +far_far_away);
330
331 glEnable(GL_BLEND);
332 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
333
334 GLfloat light_diffuse[] = {1.0, 1.0, 1.0, 1.0};
335 GLfloat light_position0[] = {-1.0, +1.0, +1.0, 0.0};
336 GLfloat light_position1[] = {+1.0, -1.0, -1.0, 0.0};
337
338 glMatrixMode(GL_MODELVIEW);
339 glLoadIdentity();
340 glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
341 glLightfv(GL_LIGHT0, GL_POSITION, light_position0);
342 glEnable(GL_LIGHT0);
343 glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
344 glLightfv(GL_LIGHT1, GL_POSITION, light_position1);
345 glEnable(GL_LIGHT1);
346 glEnable(GL_LIGHTING);
347 glEnable(GL_NORMALIZE);
348
349 glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
350 // The following line is reported to fix issue #71
351 glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 64);
352 glEnable(GL_COLOR_MATERIAL);
353 #ifdef ENABLE_OPENCSG
354 enable_opencsg_shaders();
355 #endif
356 }
357
showSmallaxes(const Color4f & col)358 void GLView::showSmallaxes(const Color4f &col)
359 {
360 auto dpi = this->getDPI();
361 // Small axis cross in the lower left corner
362 glDepthFunc(GL_ALWAYS);
363
364 // Set up an orthographic projection of the axis cross in the corner
365 glMatrixMode(GL_PROJECTION);
366 glLoadIdentity();
367 glTranslatef(-0.8f, -0.8f, 0.0f);
368 auto scale = 90;
369 glOrtho(-scale*dpi*aspectratio,scale*dpi*aspectratio,
370 -scale*dpi,scale*dpi,
371 -scale*dpi,scale*dpi);
372 gluLookAt(0.0, -1.0, 0.0,
373 0.0, 0.0, 0.0,
374 0.0, 0.0, 1.0);
375
376 glMatrixMode(GL_MODELVIEW);
377 glLoadIdentity();
378 glRotated(cam.object_rot.x(), 1.0, 0.0, 0.0);
379 glRotated(cam.object_rot.y(), 0.0, 1.0, 0.0);
380 glRotated(cam.object_rot.z(), 0.0, 0.0, 1.0);
381
382 glLineWidth(dpi);
383 glBegin(GL_LINES);
384 glColor3d(1.0, 0.0, 0.0);
385 glVertex3d(0, 0, 0); glVertex3d(10*dpi, 0, 0);
386 glColor3d(0.0, 1.0, 0.0);
387 glVertex3d(0, 0, 0); glVertex3d(0, 10*dpi, 0);
388 glColor3d(0.0, 0.0, 1.0);
389 glVertex3d(0, 0, 0); glVertex3d(0, 0, 10*dpi);
390 glEnd();
391
392 GLdouble mat_model[16];
393 glGetDoublev(GL_MODELVIEW_MATRIX, mat_model);
394
395 GLdouble mat_proj[16];
396 glGetDoublev(GL_PROJECTION_MATRIX, mat_proj);
397
398 GLint viewport[4];
399 glGetIntegerv(GL_VIEWPORT, viewport);
400
401 GLdouble xlabel_x, xlabel_y, xlabel_z;
402 gluProject(12*dpi, 0, 0, mat_model, mat_proj, viewport, &xlabel_x, &xlabel_y, &xlabel_z);
403 xlabel_x = std::round(xlabel_x); xlabel_y = std::round(xlabel_y);
404
405 GLdouble ylabel_x, ylabel_y, ylabel_z;
406 gluProject(0, 12*dpi, 0, mat_model, mat_proj, viewport, &ylabel_x, &ylabel_y, &ylabel_z);
407 ylabel_x = std::round(ylabel_x); ylabel_y = std::round(ylabel_y);
408
409 GLdouble zlabel_x, zlabel_y, zlabel_z;
410 gluProject(0, 0, 12*dpi, mat_model, mat_proj, viewport, &zlabel_x, &zlabel_y, &zlabel_z);
411 zlabel_x = std::round(zlabel_x); zlabel_y = std::round(zlabel_y);
412
413 glMatrixMode(GL_PROJECTION);
414 glLoadIdentity();
415 glTranslated(-1, -1, 0);
416 glScaled(2.0/viewport[2], 2.0/viewport[3], 1);
417
418 glMatrixMode(GL_MODELVIEW);
419 glLoadIdentity();
420
421 glColor3f(col[0], col[1], col[2]);
422
423 float d = 3*dpi;
424 glBegin(GL_LINES);
425 // X Label
426 glVertex3d(xlabel_x-d, xlabel_y-d, 0); glVertex3d(xlabel_x+d, xlabel_y+d, 0);
427 glVertex3d(xlabel_x-d, xlabel_y+d, 0); glVertex3d(xlabel_x+d, xlabel_y-d, 0);
428 // Y Label
429 glVertex3d(ylabel_x-d, ylabel_y-d, 0); glVertex3d(ylabel_x+d, ylabel_y+d, 0);
430 glVertex3d(ylabel_x-d, ylabel_y+d, 0); glVertex3d(ylabel_x, ylabel_y, 0);
431 // Z Label
432 glVertex3d(zlabel_x-d, zlabel_y-d, 0); glVertex3d(zlabel_x+d, zlabel_y-d, 0);
433 glVertex3d(zlabel_x-d, zlabel_y+d, 0); glVertex3d(zlabel_x+d, zlabel_y+d, 0);
434 glVertex3d(zlabel_x-d, zlabel_y-d, 0); glVertex3d(zlabel_x+d, zlabel_y+d, 0);
435 glEnd();
436 }
437
showAxes(const Color4f & col)438 void GLView::showAxes(const Color4f &col)
439 {
440 auto l = cam.zoomValue();
441
442 // Large gray axis cross inline with the model
443 glLineWidth(this->getDPI());
444 glColor3f(col[0], col[1], col[2]);
445
446 glBegin(GL_LINES);
447 glVertex3d(0, 0, 0);
448 glVertex3d(+l, 0, 0);
449 glVertex3d(0, 0, 0);
450 glVertex3d(0, +l, 0);
451 glVertex3d(0, 0, 0);
452 glVertex3d(0, 0, +l);
453 glEnd();
454
455 glPushAttrib(GL_LINE_BIT);
456 glEnable(GL_LINE_STIPPLE);
457 glLineStipple(3, 0xAAAA);
458 glBegin(GL_LINES);
459 glVertex3d(0, 0, 0);
460 glVertex3d(-l, 0, 0);
461 glVertex3d(0, 0, 0);
462 glVertex3d(0, -l, 0);
463 glVertex3d(0, 0, 0);
464 glVertex3d(0, 0, -l);
465 glEnd();
466 glPopAttrib();
467 }
468
showCrosshairs(const Color4f & col)469 void GLView::showCrosshairs(const Color4f &col)
470 {
471 glLineWidth(this->getDPI());
472 glColor3f(col[0], col[1], col[2]);
473 glBegin(GL_LINES);
474 for (double xf = -1; xf <= +1; xf += 2)
475 for (double yf = -1; yf <= +1; yf += 2) {
476 auto vd = cam.zoomValue()/8;
477 glVertex3d(-xf*vd, -yf*vd, -vd);
478 glVertex3d(+xf*vd, +yf*vd, +vd);
479 }
480 glEnd();
481 }
482
showScalemarkers(const Color4f & col)483 void GLView::showScalemarkers(const Color4f &col)
484 {
485 // Add scale ticks on large axes
486 auto l = cam.zoomValue();
487 glLineWidth(this->getDPI());
488 glColor3f(col[0], col[1], col[2]);
489
490 // Take log of l, discretize, then exponentiate. This is done so that the tick
491 // denominations change every time the viewport gets 10x bigger or smaller,
492 // but stays constant in-between. l_adjusted is a step function of l.
493 const int log_l = static_cast<int>(floor(log10(l)));
494 const double l_adjusted = pow(10, log_l);
495
496 // Calculate tick width.
497 const double tick_width = l_adjusted / 10.0;
498
499 const int size_div_sm = 60; // divisor for l to determine minor tick size
500 int line_cnt = 0;
501 for (double i=0; i<l; i+=tick_width){ // i represents the position along the axis
502 int size_div;
503 if (line_cnt > 0 && line_cnt % 10 == 0){ // major tick
504 size_div = size_div_sm * .5; // resize to a major tick
505 GLView::decodeMarkerValue(i, l, size_div_sm); // print number
506 } else { // minor tick
507 size_div = size_div_sm; // set the minor tick to the standard size
508
509 // Draw additional labels if there are few major tick labels visible due to
510 // zoom. Because the spacing/units of major tick marks only change when the
511 // viewport changes size by a factor of 10, it can be hard to see the
512 // major tick labels when when the viewport is slightly larger than size at
513 // which the last tick spacing change occurred. When zoom level is such
514 // that very few major tick marks are visible, additional labels are drawn
515 // every 2 minor ticks. We can detect that very few major ticks are visible
516 // by checking if the viewport size is larger than the adjusted scale by
517 // only a small ratio.
518 const double more_labels_threshold = 3;
519 // draw additional labels every 2 minor ticks
520 const int more_labels_freq = 2;
521 if (line_cnt > 0 && line_cnt % more_labels_freq == 0 && l / l_adjusted < more_labels_threshold) {
522 GLView::decodeMarkerValue(i, l, size_div_sm); // print number
523 }
524 }
525 line_cnt++;
526
527 /*
528 * The length of each tick is proportional to the length of the axis
529 * (which changes with the zoom value.) l/size_div provides the
530 * proportional length
531 *
532 * Commented glVertex3d lines provide additional 'arms' for the tick
533 * the number of arms will (hopefully) eventually be driven via Preferences
534 */
535
536 // positive axes
537 glBegin(GL_LINES);
538 // x
539 glVertex3d(i,0,0); glVertex3d(i,-l/size_div,0); // 1 arm
540 //glVertex3d(i,-l/size_div,0); glVertex3d(i,l/size_div,0); // 2 arms
541 //glVertex3d(i,0,-l/size_div); glVertex3d(i,0,l/size_div); // 4 arms (w/ 2 arms line)
542
543 // y
544 glVertex3d(0,i,0); glVertex3d(-l/size_div,i,0); // 1 arm
545 //glVertex3d(-l/size_div,i,0); glVertex3d(l/size_div,i,0); // 2 arms
546 //glVertex3d(0,i,-l/size_div); glVertex3d(0,i,l/size_div); // 4 arms (w/ 2 arms line)
547
548 // z
549 glVertex3d(0,0,i); glVertex3d(-l/size_div,0,i); // 1 arm
550 //glVertex3d(-l/size_div,0,i); glVertex3d(l/size_div,0,i); // 2 arms
551 //glVertex3d(0,-l/size_div,i); glVertex3d(0,l/size_div,i); // 4 arms (w/ 2 arms line)
552 glEnd();
553
554 // negative axes
555 glPushAttrib(GL_LINE_BIT);
556 glEnable(GL_LINE_STIPPLE);
557 glLineStipple(3, 0xAAAA);
558 glBegin(GL_LINES);
559 // x
560 glVertex3d(-i,0,0); glVertex3d(-i,-l/size_div,0); // 1 arm
561 //glVertex3d(-i,-l/size_div,0); glVertex3d(-i,l/size_div,0); // 2 arms
562 //glVertex3d(-i,0,-l/size_div); glVertex3d(-i,0,l/size_div); // 4 arms (w/ 2 arms line)
563
564 // y
565 glVertex3d(0,-i,0); glVertex3d(-l/size_div,-i,0); // 1 arm
566 //glVertex3d(-l/size_div,-i,0); glVertex3d(l/size_div,-i,0); // 2 arms
567 //glVertex3d(0,-i,-l/size_div); glVertex3d(0,-i,l/size_div); // 4 arms (w/ 2 arms line)
568
569 // z
570 glVertex3d(0,0,-i); glVertex3d(-l/size_div,0,-i); // 1 arm
571 //glVertex3d(-l/size_div,0,-i); glVertex3d(l/size_div,0,-i); // 2 arms
572 //glVertex3d(0,-l/size_div,-i); glVertex3d(0,l/size_div,-i); // 4 arms (w/ 2 arms line)
573 glEnd();
574 glPopAttrib();
575 }
576 }
577
decodeMarkerValue(double i,double l,int size_div_sm)578 void GLView::decodeMarkerValue(double i, double l, int size_div_sm)
579 {
580 const auto unsigned_digit = STR(i);
581
582 // setup how far above the axis (or tick TBD) to draw the number
583 double dig_buf = (l/size_div_sm)/4;
584 // setup the size of the character box
585 double dig_w = (l/size_div_sm)/2;
586 double dig_h = (l/size_div_sm) + dig_buf;
587 // setup the distance between characters
588 double kern = dig_buf;
589 double dig_wk = (dig_w) + kern;
590
591 // set up ordering for different axes
592 int ax[6][3] = {
593 {0,1,2},
594 {1,0,2},
595 {1,2,0},
596 {0,1,2},
597 {1,0,2},
598 {1,2,0}};
599
600 // set up character vertex sequences for different axes
601 int or_2[6][6]={
602 {0,1,3,2,4,5},
603 {1,0,2,3,5,4},
604 {1,0,2,3,5,4},
605 {1,0,2,3,5,4},
606 {0,1,3,2,4,5},
607 {0,1,3,2,4,5}};
608
609 int or_3[6][7]={
610 {0,1,3,2,3,5,4},
611 {1,0,2,3,2,4,5},
612 {1,0,2,3,2,4,5},
613 {1,0,2,3,2,4,5},
614 {0,1,3,2,3,5,4},
615 {0,1,3,2,3,5,4}};
616
617 int or_4[6][5]={
618 {0,2,3,1,5},
619 {1,3,2,0,4},
620 {1,3,2,0,4},
621 {1,3,2,0,4},
622 {0,2,3,1,5},
623 {0,2,3,1,5}};
624
625 int or_5[6][6]={
626 {1,0,2,3,5,4},
627 {0,1,3,2,4,5},
628 {0,1,3,2,4,5},
629 {0,1,3,2,4,5},
630 {1,0,2,3,5,4},
631 {1,0,2,3,5,4}};
632
633 int or_6[6][6]={
634 {1,0,4,5,3,2},
635 {0,1,5,4,2,3},
636 {0,1,5,4,2,3},
637 {0,1,5,4,2,3},
638 {1,0,4,5,3,2},
639 {1,0,4,5,3,2}};
640
641 int or_7[6][3]={
642 {0,1,4},
643 {1,0,5},
644 {1,0,5},
645 {1,0,5},
646 {0,1,4},
647 {0,1,4}};
648
649 int or_9[6][5]={
650 {5,1,0,2,3},
651 {4,0,1,3,2},
652 {4,0,1,3,2},
653 {4,0,1,3,2},
654 {5,1,0,2,3},
655 {5,1,0,2,3}};
656
657 int or_e[6][7]={
658 {1,0,2,3,2,4,5},
659 {0,1,3,2,3,5,4},
660 {0,1,3,2,3,5,4},
661 {0,1,3,2,3,5,4},
662 {1,0,2,3,2,4,5},
663 {1,0,2,3,2,4,5}};
664
665 // walk through axes
666 for (int di=0; di<6; ++di){
667
668 // setup negative axes
669 double polarity = 1;
670 auto digit = unsigned_digit;
671 if (di>2){
672 polarity = -1;
673 digit.insert(0, "-");
674 }
675
676 // fix the axes that need to run the opposite direction
677 if (di>0 && di<4){
678 std::reverse(digit.begin(),digit.end());
679 }
680
681 // walk through and render the characters of the string
682 for(std::string::size_type char_num = 0; char_num < digit.size(); ++char_num){
683 // setup the vertices for the char rendering based on the axis and position
684 double dig_vrt[6][3] = {
685 {polarity*((i+((char_num)*dig_wk))-(dig_w/2)),dig_h,0},
686 {polarity*((i+((char_num)*dig_wk))+(dig_w/2)),dig_h,0},
687 {polarity*((i+((char_num)*dig_wk))-(dig_w/2)),dig_h/2+dig_buf,0},
688 {polarity*((i+((char_num)*dig_wk))+(dig_w/2)),dig_h/2+dig_buf,0},
689 {polarity*((i+((char_num)*dig_wk))-(dig_w/2)),dig_buf,0},
690 {polarity*((i+((char_num)*dig_wk))+(dig_w/2)),dig_buf,0}};
691
692 // convert the char into lines appropriate for the axis being used
693 // pseudo 7 segment vertices are:
694 // A--B
695 // | |
696 // C--D
697 // | |
698 // E--F
699 switch(digit[char_num]){
700 case '1':
701 glBegin(GL_LINES);
702 glVertex3d(dig_vrt[0][ax[di][0]],dig_vrt[0][ax[di][1]],dig_vrt[0][ax[di][2]]); //a
703 glVertex3d(dig_vrt[4][ax[di][0]],dig_vrt[4][ax[di][1]],dig_vrt[4][ax[di][2]]); //e
704 glEnd();
705 break;
706
707 case '2':
708 glBegin(GL_LINE_STRIP);
709 glVertex3d(dig_vrt[or_2[di][0]][ax[di][0]],dig_vrt[or_2[di][0]][ax[di][1]],dig_vrt[or_2[di][0]][ax[di][2]]); //a
710 glVertex3d(dig_vrt[or_2[di][1]][ax[di][0]],dig_vrt[or_2[di][1]][ax[di][1]],dig_vrt[or_2[di][1]][ax[di][2]]); //b
711 glVertex3d(dig_vrt[or_2[di][2]][ax[di][0]],dig_vrt[or_2[di][2]][ax[di][1]],dig_vrt[or_2[di][2]][ax[di][2]]); //d
712 glVertex3d(dig_vrt[or_2[di][3]][ax[di][0]],dig_vrt[or_2[di][3]][ax[di][1]],dig_vrt[or_2[di][3]][ax[di][2]]); //c
713 glVertex3d(dig_vrt[or_2[di][4]][ax[di][0]],dig_vrt[or_2[di][4]][ax[di][1]],dig_vrt[or_2[di][4]][ax[di][2]]); //e
714 glVertex3d(dig_vrt[or_2[di][5]][ax[di][0]],dig_vrt[or_2[di][5]][ax[di][1]],dig_vrt[or_2[di][5]][ax[di][2]]); //f
715 glEnd();
716 break;
717
718 case '3':
719 glBegin(GL_LINE_STRIP);
720 glVertex3d(dig_vrt[or_3[di][0]][ax[di][0]],dig_vrt[or_3[di][0]][ax[di][1]],dig_vrt[or_3[di][0]][ax[di][2]]); //a
721 glVertex3d(dig_vrt[or_3[di][1]][ax[di][0]],dig_vrt[or_3[di][1]][ax[di][1]],dig_vrt[or_3[di][1]][ax[di][2]]); //b
722 glVertex3d(dig_vrt[or_3[di][2]][ax[di][0]],dig_vrt[or_3[di][2]][ax[di][1]],dig_vrt[or_3[di][2]][ax[di][2]]); //d
723 glVertex3d(dig_vrt[or_3[di][3]][ax[di][0]],dig_vrt[or_3[di][3]][ax[di][1]],dig_vrt[or_3[di][3]][ax[di][2]]); //c
724 glVertex3d(dig_vrt[or_3[di][4]][ax[di][0]],dig_vrt[or_3[di][4]][ax[di][1]],dig_vrt[or_3[di][4]][ax[di][2]]); //d
725 glVertex3d(dig_vrt[or_3[di][5]][ax[di][0]],dig_vrt[or_3[di][5]][ax[di][1]],dig_vrt[or_3[di][5]][ax[di][2]]); //f
726 glVertex3d(dig_vrt[or_3[di][6]][ax[di][0]],dig_vrt[or_3[di][6]][ax[di][1]],dig_vrt[or_3[di][6]][ax[di][2]]); //e
727 glEnd();
728 break;
729
730 case '4':
731 glBegin(GL_LINE_STRIP);
732 glVertex3d(dig_vrt[or_4[di][0]][ax[di][0]],dig_vrt[or_4[di][0]][ax[di][1]],dig_vrt[or_4[di][0]][ax[di][2]]); //a
733 glVertex3d(dig_vrt[or_4[di][1]][ax[di][0]],dig_vrt[or_4[di][1]][ax[di][1]],dig_vrt[or_4[di][1]][ax[di][2]]); //c
734 glVertex3d(dig_vrt[or_4[di][2]][ax[di][0]],dig_vrt[or_4[di][2]][ax[di][1]],dig_vrt[or_4[di][2]][ax[di][2]]); //d
735 glVertex3d(dig_vrt[or_4[di][3]][ax[di][0]],dig_vrt[or_4[di][3]][ax[di][1]],dig_vrt[or_4[di][3]][ax[di][2]]); //b
736 glVertex3d(dig_vrt[or_4[di][4]][ax[di][0]],dig_vrt[or_4[di][4]][ax[di][1]],dig_vrt[or_4[di][4]][ax[di][2]]); //f
737 glEnd();
738 break;
739
740 case '5':
741 glBegin(GL_LINE_STRIP);
742 glVertex3d(dig_vrt[or_5[di][0]][ax[di][0]],dig_vrt[or_5[di][0]][ax[di][1]],dig_vrt[or_5[di][0]][ax[di][2]]); //b
743 glVertex3d(dig_vrt[or_5[di][1]][ax[di][0]],dig_vrt[or_5[di][1]][ax[di][1]],dig_vrt[or_5[di][1]][ax[di][2]]); //a
744 glVertex3d(dig_vrt[or_5[di][2]][ax[di][0]],dig_vrt[or_5[di][2]][ax[di][1]],dig_vrt[or_5[di][2]][ax[di][2]]); //c
745 glVertex3d(dig_vrt[or_5[di][3]][ax[di][0]],dig_vrt[or_5[di][3]][ax[di][1]],dig_vrt[or_5[di][3]][ax[di][2]]); //d
746 glVertex3d(dig_vrt[or_5[di][4]][ax[di][0]],dig_vrt[or_5[di][4]][ax[di][1]],dig_vrt[or_5[di][4]][ax[di][2]]); //f
747 glVertex3d(dig_vrt[or_5[di][5]][ax[di][0]],dig_vrt[or_5[di][5]][ax[di][1]],dig_vrt[or_5[di][5]][ax[di][2]]); //e
748 glEnd();
749 break;
750
751 case '6':
752 glBegin(GL_LINE_STRIP);
753 glVertex3d(dig_vrt[or_6[di][0]][ax[di][0]],dig_vrt[or_6[di][0]][ax[di][1]],dig_vrt[or_6[di][0]][ax[di][2]]); //b
754 glVertex3d(dig_vrt[or_6[di][1]][ax[di][0]],dig_vrt[or_6[di][1]][ax[di][1]],dig_vrt[or_6[di][1]][ax[di][2]]); //a
755 glVertex3d(dig_vrt[or_6[di][2]][ax[di][0]],dig_vrt[or_6[di][2]][ax[di][1]],dig_vrt[or_6[di][2]][ax[di][2]]); //e
756 glVertex3d(dig_vrt[or_6[di][3]][ax[di][0]],dig_vrt[or_6[di][3]][ax[di][1]],dig_vrt[or_6[di][3]][ax[di][2]]); //f
757 glVertex3d(dig_vrt[or_6[di][4]][ax[di][0]],dig_vrt[or_6[di][4]][ax[di][1]],dig_vrt[or_6[di][4]][ax[di][2]]); //d
758 glVertex3d(dig_vrt[or_6[di][5]][ax[di][0]],dig_vrt[or_6[di][5]][ax[di][1]],dig_vrt[or_6[di][5]][ax[di][2]]); //c
759 glEnd();
760 break;
761
762 case '7':
763 glBegin(GL_LINE_STRIP);
764 glVertex3d(dig_vrt[or_7[di][0]][ax[di][0]],dig_vrt[or_7[di][0]][ax[di][1]],dig_vrt[or_7[di][0]][ax[di][2]]); //a
765 glVertex3d(dig_vrt[or_7[di][1]][ax[di][0]],dig_vrt[or_7[di][1]][ax[di][1]],dig_vrt[or_7[di][1]][ax[di][2]]); //b
766 glVertex3d(dig_vrt[or_7[di][2]][ax[di][0]],dig_vrt[or_7[di][2]][ax[di][1]],dig_vrt[or_7[di][2]][ax[di][2]]); //e
767 glEnd();
768 break;
769
770 case '8':
771 glBegin(GL_LINE_STRIP);
772 glVertex3d(dig_vrt[2][ax[di][0]],dig_vrt[2][ax[di][1]],dig_vrt[2][ax[di][2]]); //c
773 glVertex3d(dig_vrt[3][ax[di][0]],dig_vrt[3][ax[di][1]],dig_vrt[3][ax[di][2]]); //d
774 glVertex3d(dig_vrt[1][ax[di][0]],dig_vrt[1][ax[di][1]],dig_vrt[1][ax[di][2]]); //b
775 glVertex3d(dig_vrt[0][ax[di][0]],dig_vrt[0][ax[di][1]],dig_vrt[0][ax[di][2]]); //a
776 glVertex3d(dig_vrt[4][ax[di][0]],dig_vrt[4][ax[di][1]],dig_vrt[4][ax[di][2]]); //e
777 glVertex3d(dig_vrt[5][ax[di][0]],dig_vrt[5][ax[di][1]],dig_vrt[5][ax[di][2]]); //f
778 glVertex3d(dig_vrt[3][ax[di][0]],dig_vrt[3][ax[di][1]],dig_vrt[3][ax[di][2]]); //d
779 glEnd();
780 break;
781
782 case '9':
783 glBegin(GL_LINE_STRIP);
784 glVertex3d(dig_vrt[or_9[di][0]][ax[di][0]],dig_vrt[or_9[di][0]][ax[di][1]],dig_vrt[or_9[di][0]][ax[di][2]]); //f
785 glVertex3d(dig_vrt[or_9[di][1]][ax[di][0]],dig_vrt[or_9[di][1]][ax[di][1]],dig_vrt[or_9[di][1]][ax[di][2]]); //b
786 glVertex3d(dig_vrt[or_9[di][2]][ax[di][0]],dig_vrt[or_9[di][2]][ax[di][1]],dig_vrt[or_9[di][2]][ax[di][2]]); //a
787 glVertex3d(dig_vrt[or_9[di][3]][ax[di][0]],dig_vrt[or_9[di][3]][ax[di][1]],dig_vrt[or_9[di][3]][ax[di][2]]); //c
788 glVertex3d(dig_vrt[or_9[di][4]][ax[di][0]],dig_vrt[or_9[di][4]][ax[di][1]],dig_vrt[or_9[di][4]][ax[di][2]]); //d
789 glEnd();
790 break;
791
792 case '0':
793 glBegin(GL_LINE_LOOP);
794 glVertex3d(dig_vrt[0][ax[di][0]],dig_vrt[0][ax[di][1]],dig_vrt[0][ax[di][2]]); //a
795 glVertex3d(dig_vrt[1][ax[di][0]],dig_vrt[1][ax[di][1]],dig_vrt[1][ax[di][2]]); //b
796 glVertex3d(dig_vrt[5][ax[di][0]],dig_vrt[5][ax[di][1]],dig_vrt[5][ax[di][2]]); //f
797 glVertex3d(dig_vrt[4][ax[di][0]],dig_vrt[4][ax[di][1]],dig_vrt[4][ax[di][2]]); //e
798 glEnd();
799 break;
800
801 case '-':
802 glBegin(GL_LINES);
803 glVertex3d(dig_vrt[2][ax[di][0]],dig_vrt[2][ax[di][1]],dig_vrt[2][ax[di][2]]); //c
804 glVertex3d(dig_vrt[3][ax[di][0]],dig_vrt[3][ax[di][1]],dig_vrt[3][ax[di][2]]); //d
805 glEnd();
806 break;
807
808 case '.':
809 glBegin(GL_LINES);
810 glVertex3d(dig_vrt[4][ax[di][0]],dig_vrt[4][ax[di][1]],dig_vrt[4][ax[di][2]]); //e
811 glVertex3d(dig_vrt[5][ax[di][0]],dig_vrt[5][ax[di][1]],dig_vrt[5][ax[di][2]]); //f
812 glEnd();
813 break;
814
815 case 'e':
816 glBegin(GL_LINE_STRIP);
817 glVertex3d(dig_vrt[or_e[di][0]][ax[di][0]],dig_vrt[or_e[di][0]][ax[di][1]],dig_vrt[or_e[di][0]][ax[di][2]]); //b
818 glVertex3d(dig_vrt[or_e[di][1]][ax[di][0]],dig_vrt[or_e[di][1]][ax[di][1]],dig_vrt[or_e[di][1]][ax[di][2]]); //a
819 glVertex3d(dig_vrt[or_e[di][2]][ax[di][0]],dig_vrt[or_e[di][2]][ax[di][1]],dig_vrt[or_e[di][2]][ax[di][2]]); //c
820 glVertex3d(dig_vrt[or_e[di][3]][ax[di][0]],dig_vrt[or_e[di][3]][ax[di][1]],dig_vrt[or_e[di][3]][ax[di][2]]); //d
821 glVertex3d(dig_vrt[or_e[di][4]][ax[di][0]],dig_vrt[or_e[di][4]][ax[di][1]],dig_vrt[or_e[di][4]][ax[di][2]]); //c
822 glVertex3d(dig_vrt[or_e[di][5]][ax[di][0]],dig_vrt[or_e[di][5]][ax[di][1]],dig_vrt[or_e[di][5]][ax[di][2]]); //e
823 glVertex3d(dig_vrt[or_e[di][6]][ax[di][0]],dig_vrt[or_e[di][6]][ax[di][1]],dig_vrt[or_e[di][6]][ax[di][2]]); //f
824 glEnd();
825 break;
826
827 }
828 }
829 }
830 }
831
832