Simple Graphics Library  0.9.5
SGL API
sgl.hpp
1 
49 #ifndef SGL_HPP_
50 #define SGL_HPP_
51 
52 //#ifdef _MSC_VER
53 // #pragma warning(disable:4251)
54 // #pragma warning(disable:4224)
55 // #pragma warning(disable:4458)
56 //#endif
57 
58 #ifdef _MSC_VER
59  #pragma warning(push, 3)
60 #endif
61 
62 //#include <sstream>
63 #include <cmath>
64 #include <cstdlib> // Linux requires cstdlib for exit and rand functions
65 //#include <cstring>
66 //#include <memory>
67 #include <algorithm>
68 #include <GL/sgl.h>
69 #ifdef __APPLE__
70 #include <GLUT/glut.h>
71 #else
72 #include <GL/glut.h>
73 #endif
74 
79 namespace sgl {
80 
81 static const std::string SGL_VERSION_NUMBER = "0.9.5 (February 17, 2019)";
82 
83 
84 static bool glut_active = false;
85 static bool event_loop_running = false;
86 
87 
88 
89 //static Window *current_window = nullptr; // Current window intially null
90 
91 // Maximum number of windows managed by SGL
92 const int MAX_WINDOWS = 10;
93 // List of windows managed by SGL
94 static Window *window_list[] = {
95  nullptr, // Index 0 is unused
96  nullptr,
97  nullptr,
98  nullptr,
99  nullptr,
100  nullptr,
101  nullptr,
102  nullptr,
103  nullptr,
104  nullptr,
105  nullptr
106 };
107 
108 // Some coordinate conversion helper functions
109 static void GetOGLPos(int x, int y, double *vec) {
110  GLint viewport[4];
111  GLdouble modelview[16];
112  GLdouble projection[16];
113  GLfloat winX, winY, winZ;
114  GLdouble posX, posY, posZ;
115 
116  glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
117  glGetDoublev(GL_PROJECTION_MATRIX, projection);
118  glGetIntegerv(GL_VIEWPORT, viewport);
119 
120  winX = static_cast<float>(x);
121  winY = static_cast<float>(viewport[3] - y);
122  glReadPixels(x, static_cast<int>(winY), 1, 1,
123  GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
124 
125  gluUnProject(winX, winY, winZ, modelview, projection, viewport,
126  &posX, &posY, &posZ);
127 
128  vec[0] = posX; vec[1] = posY; vec[2] = posZ;
129 }
130 
131 static void convert(int mx, int my, double &vx, double &vy) {
132  // Determine viewport coordinates
133  double mouse_vector[3];
134  GetOGLPos(mx, my, mouse_vector);
135  vx = mouse_vector[0];
136  vy = mouse_vector[1];
137 }
138 
148 void initialize_graphics(unsigned int mode) {
149  if (!glut_active) {
150  // Make up a dummy program name and pass no additional arguments
151  static int argc = 1;
152  static char *argv[] = { const_cast<char *>("sgl_program") };
153  glutInit(&argc, argv);
154  glutInitDisplayMode(mode);
155  glut_active = true;
156  }
157  else {
158  std::cout << "Graphics environment already initialized\n";
159  exit(1);
160  }
161 }
162 
173  initialize_graphics(GLUT_DOUBLE | GLUT_RGB);
174 }
175 
176 
177 /* ***********
178 // Global inialization function, called once per program execution
179 void initialize_graphics()
180 {
181  if ( !glut_active )
182  {
183  // Make up a dummy program name and pass no additional arguments
184  static int argc = 1;
185  static char *argv[] = { "sgl_program" };
186  glutInit(&argc, argv);
187  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
188  glut_active = true;
189  }
190  else
191  {
192  std::cout << "Graphics environment already initialized\n";
193  exit(1);
194  }
195 }
196 ******************** */
197 
198 
199 // Returns the version number of SGL
200 std::string version() {
201  return SGL_VERSION_NUMBER;
202 }
203 
204 
205 /*****************************************************
206  * Global GLUT callback functions
207  *****************************************************/
208 
209 static void sgl_display() {
210  if (window_list[glutGetWindow()])
211  window_list[glutGetWindow()]->paint_all();
212 }
213 
214 static void sgl_reshape(int w, int h) {
215  window_list[glutGetWindow()]->resized(w, h);
216 }
217 
218 static void sgl_mouse_dragged(int x, int y) {
219  double vx, vy;
220  convert(x, y, vx, vy);
221  window_list[glutGetWindow()]->mouse_dragged(vx, vy);
222 }
223 
224 
225 static void sgl_mouse_moved(int x, int y) {
226  double vx, vy;
227  convert(x, y, vx, vy);
228  window_list[glutGetWindow()]->mouse_moved(vx, vy);
229 }
230 
231 static void sgl_mouse_entry(int state) {
232  if (state == GLUT_LEFT)
233  window_list[glutGetWindow()]->mouse_exited();
234  else
235  window_list[glutGetWindow()]->mouse_entered();
236 }
237 
238 
239 static void sgl_timer_expired(int win_number) {
240  //current_window->timer_expired(msec);
241  //std::cout << "Sending a timer message to window #"
242  // << glutGetWindow() << " (" << win_number << ")\n";
243  //window_list[glutGetWindow()]->timer_expired(msec);
244  window_list[win_number]->timer_expired();
245 }
246 
247 
248 static void sgl_mouse_button(int button, int state, int x, int y) {
249  double vx, vy;
250  convert(x, y, vx, vy);
251  //std::cout << "(" << vx << "," << vy << ")\n";
252 
253  Window *win = window_list[glutGetWindow()];
254 
255  win->set_key_modifiers(static_cast<KeyModifier>(glutGetModifiers()));
256 
257  if (state == GLUT_DOWN)
258  win->mouse_pressed(vx, vy, static_cast<MouseButton>(button));
259  else if (state == GLUT_UP)
260  win->mouse_released(vx, vy, static_cast<MouseButton>(button));
261 }
262 
263 
264 
265 static void sgl_key_pressed(unsigned char k, int x, int y) {
266  double vx, vy;
267  convert(x, y, vx, vy);
268  Window *win = window_list[glutGetWindow()];
269  win->set_key_modifiers(static_cast<KeyModifier>(glutGetModifiers()));
270  win->key_pressed(k, vx, vy);
271 }
272 
273 static void sgl_special_key_pressed(int k, int x, int y) {
274  double vx, vy;
275  convert(x, y, vx, vy);
276  Window *win = window_list[glutGetWindow()];
277  win->set_key_modifiers(static_cast<KeyModifier>(glutGetModifiers()));
278  win->key_pressed(k + 10000, vx, vy);
279  //current_window->special_key_pressed(k, vx, vy);
280 }
281 
282 
283 /*****************************************************
284  * Global constant Color objects
285  *****************************************************/
286 
287 const Color BLACK(0.0, 0.0, 0.0);
288 const Color RED(1.0, 0.0, 0.0);
289 const Color GREEN(0.0, 1.0, 0.0);
290 const Color BLUE(0.0, 0.0, 1.0);
291 const Color YELLOW(1.0, 1.0, 0.0);
292 const Color MAGENTA(1.0, 0.0, 1.0);
293 const Color CYAN(0.0, 1.0, 1.0);
294 const Color DARK_RED(0.75, 0.0, 0.0);
295 const Color DARK_GREEN(0.0, 0.75, 0.0);
296 const Color DARK_BLUE(0.0, 0.0, 0.75);
297 const Color LIGHT_RED(1.0, 0.75, 0.75);
298 const Color LIGHT_GREEN(0.75, 1.0, 0.75);
299 const Color LIGHT_BLUE(0.75, 0.75, 1.0);
300 const Color GRAY(0.5, 0.5, 0.5);
301 const Color LIGHT_GRAY(0.8, 0.8, 0.8);
302 const Color DARK_GRAY(0.2, 0.2, 0.2);
303 const Color WHITE(1.0, 1.0, 1.0);
304 
305 
306 /*****************************************************
307  * Graphical object code
308  *****************************************************/
309 
310 
311 void Window::initialize(const std::string& title, int left, int top, int width, int height,
312  double min_x, double max_x, double min_y, double max_y) {
313  // Check for proper window dimensions
314  if (max_x - min_x <= 0 || max_y - min_y <= 0)
315  std::cout << "WARNING: Horizontal and/or vertical window dimensions "
316  << "zero or negative (check constructor arguments)\n";
317  // Must initialize graphics for the first window created if
318  // it has not been done already
319  if (!glut_active)
321 
322  glutInitWindowSize(width, height);
323  glutInitWindowPosition(left, top);
324  //std::cout << "Creating window #" << glutCreateWindow(title) << '\n';
325  glutCreateWindow(title.c_str());
326  glClearColor(1.0, 1.0, 1.0, 0.0); // White background
327  glShadeModel(GL_FLAT);
328 
329  // Set window dimension globals
330  this->min_x = min_x;
331  this->min_y = min_y;
332  this->max_x = max_x;
333  this->max_y = max_y;
334 
335  set_viewport(min_x, min_y, max_x, max_y);
336 
337 
338  glutDisplayFunc(sgl_display);
339  glutReshapeFunc(sgl_reshape);
340  glutMotionFunc(sgl_mouse_dragged);
341  glutPassiveMotionFunc(sgl_mouse_moved);
342  glutMouseFunc(sgl_mouse_button);
343  glutEntryFunc(sgl_mouse_entry);
344  glutKeyboardFunc(sgl_key_pressed);
345  glutSpecialFunc(sgl_special_key_pressed);
346 
347  normal_cursor = CursorShape::Right_arrow;
349 
350  //current_window = this;
351  window_list[glutGetWindow()] = this;
352 }
353 
354 
355 /*
356  * Constructor
357  * Creates a graphics window with a its left-top corner at (left, top) in
358  * screen coordinates. Its width is width, and its height is height. The viewport
359  * it represents extends from min_x to max_y horizontally and from min_y to max_y vertically.
360  */
361 Window::Window(const std::string& title, int left, int top, int width, int height,
362  double min_x, double max_x, double min_y, double max_y) {
363  initialize(title, left, top, width, height, min_x, max_x, min_y, max_y);
364 }
365 
366 Window::Window(const std::string& title, int width, int height) {
367  initialize(title, 100, 100, width, height, 0.0, width, 0.0, height);
368 }
369 
370 Window::Window(const std::string& title, double min_x, double max_x, double min_y, double max_y)
371 {
372  // Compute the window's size
373  double width = max_x - min_x,
374  height = max_y - min_y;
375  int window_width, window_height;
376  // Prevent the creation of a window with zero or negative
377  // dimensions
378  if (width <= 0 || height <= 0) {
379  std::cout << "Window vertical or horizontal dimension zero "
380  << "or negative; check order of constructor arguments\n";
381  exit(1);
382  }
383  // Scale physical window size so the longest side is 600 pixels
384  if (width > height) { // window is shorter and wider
385  window_width = 600;
386  // Adjust aspect ratio
387  window_height = static_cast<int>(600*height/width + 0.5);
388  }
389  else { // Window is longer and taller
390  window_height = 600;
391  // Adjust aspect ratio
392  window_width = static_cast<int>(600*width/height + 0.5);
393  }
394 
395  initialize(title, 100, 100, window_width, window_height,
396  min_x, max_x, min_y, max_y);
397 }
398 
400  initialize("", 100, 100, 600, 600, 0.0, 0.0, 600.0, 600.0);
401 }
402 
404  //current_window = nullptr;
405  window_list[glutGetWindow()] = nullptr;
406  //object_list.clear();
407 }
408 
416 void Window::set_position(int x, int y) {
417  glutPositionWindow(x, y);
418 }
419 
427 void Window::set_size(int width, int height) {
428  glutReshapeWindow(width, height);
429 }
430 
438 void Window::set_visible(bool visible) {
439  if (visible)
440  glutShowWindow();
441  else
442  glutHideWindow();
443 }
444 
451  CursorShape previous_cursor =
452  static_cast<CursorShape>(glutGet(GLUT_WINDOW_CURSOR));
453  glutSetCursor(static_cast<int>(cursor));
454  return previous_cursor;
455 }
456 
462  return static_cast<CursorShape>(glutGet(GLUT_WINDOW_CURSOR));
463 }
464 
465 
466 void Window::set_viewport(double left, double right,
467  double bottom, double top) {
468  glMatrixMode(GL_PROJECTION);
469  glLoadIdentity();
470  gluOrtho2D(left, right, bottom, top);
471 }
472 
474  glClearColor(static_cast<GLclampf>(color.red),
475  static_cast<GLclampf>(color.green),
476  static_cast<GLclampf>(color.blue),
477  0.0);
478 }
479 
480 /*
481  * Start the graphics event loop. Control is passed to the
482  * event manager and the event manager maintains control for the
483  * rest of the program's execution. This method should be called
484  * only once.
485  */
486 void Window::run() {
487  if (!event_loop_running) {
488  event_loop_running = true;
489  glutMainLoop();
490  }
491  else
492  std::cout << "Event loop already running, action ignored\n";
493 }
494 
495 
496 /*
497  * draw_axes
498  * Draws the x- and y-axes within the viewport using the current drawing color.
499  */
500 void Window::draw_axes(double x_inc, double y_inc) const {
501  // Draw grid lines at 10 unit increments
502  glColor3d(0.9, 0.9, 1.0); // Light blue
503  for (double x = 0 + x_inc; x < max_x; x += x_inc)
504  draw_line(x, min_y, x, max_y);
505  for (double y = 0 + y_inc; y < max_y; y += y_inc)
506  draw_line(min_x, y, max_x, y);
507  for (double x = -x_inc; x > min_x; x -= x_inc)
508  draw_line(x, min_y, x, max_y);
509  for (double y = -y_inc; y > min_y; y -= y_inc)
510  draw_line(min_x, y, max_x, y);
511  // Draw axes
512  glColor3d(0.0, 0.0, 0.0); // Black
513  draw_line(min_x, 0.0, max_x, 0.0); // x-axis
514  draw_line(0.0, min_y, 0.0, max_y); // y-axis
515  draw_line(min_x, 0.0, min_x + 5.0, -2.0); // x-axis left arrow head
516  draw_line(min_x, 0.0, min_x + 5.0, 2.0);
517  draw_line(max_x, 0.0, max_x - 5.0, -2.0); // x-axis right arrow head
518  draw_line(max_x, 0.0, max_x - 5.0, 2.0);
519  draw_line(0.0, min_y, -2.0, min_y + 5.0); // y-axis bottom arrow head
520  draw_line(0.0, min_y, 2.0, min_y + 5.0);
521  draw_line(0.0, max_y, -2.0, max_y - 5.0); // y-axis top arrow head
522  draw_line(0.0, max_y, 2.0, max_y - 5.0);
523 }
524 
525 
526 
527 /*
528  * clear_viewport
529  * Sets the viewport to its background color, erasing all drawings within it.
530  */
532  glClear(GL_COLOR_BUFFER_BIT);
533 }
534 
535 void Window::set_title(const std::string& str) {
536  glutSetWindowTitle(str.c_str());
537 }
538 
540  glutPostRedisplay();
541 }
542 
544  prepaint();
545  paint();
546  postpaint();
547 }
548 
550  glClear(GL_COLOR_BUFFER_BIT);
551  glPushMatrix();
552  glColor3d(0.0, 0.2, 0.0);
553 }
554 
556  glPopMatrix();
557  //glFlush();
558  glutSwapBuffers();
559 }
560 
561 
562 // Returns the x value of the left, top corner of the window
563 int Window::get_x() const {
564  return glutGet(GLUT_WINDOW_X);
565 }
566 
567 // Returns the y value of the left, top corner of the window
568 int Window::get_y() const {
569  return glutGet(GLUT_WINDOW_Y);
570 }
571 
572 // Returns the width of the window
573 int Window::get_width() const {
574  return glutGet(GLUT_WINDOW_WIDTH);
575 }
576 
577 // Returns the height of the window
578 int Window::get_height() const {
579  return glutGet(GLUT_WINDOW_HEIGHT);
580 }
581 
582 double Window::get_min_x() const {
583  return min_x;
584 }
585 
586 double Window::get_max_x() const {
587  return max_x;
588 }
589 
590 double Window::get_min_y() const {
591  return min_y;
592 }
593 
594 double Window::get_max_y() const {
595  return max_y;
596 }
597 
598 void Window::set_window_size(int w, int h) {
599  glutReshapeWindow(w, h);
600 }
601 
602 void Window::resized(int w, int h) {
603  glutInitWindowSize(w, h);
604  glViewport (0, 0, static_cast<GLsizei>(w), static_cast<GLsizei>(h));
605  glMatrixMode(GL_PROJECTION);
606  glLoadIdentity();
607  //glOrtho(min_x, max_x, min_y, max_y, -1.0, 1.0);
608  gluOrtho2D(min_x, max_x, min_y, max_y);
609  glMatrixMode(GL_MODELVIEW);
610  glLoadIdentity();
611 }
612 
613 
614 
615 void Window::mouse_moved(double, double) {}
616 
617 void Window::mouse_dragged(double, double) {}
618 
619 void Window::mouse_pressed(double, double, MouseButton) {}
620 
621 void Window::mouse_released(double, double, MouseButton) {}
622 
629 
636 
637 /*
638  * Alt-F4 closes the window and terminates the program. Derived classes
639  * should call this version to ensure consistent behavior.
640  */
641 void Window::key_pressed(int key, double, double) {
642  if (key == F4_KEY && glutGetModifiers() == GLUT_ACTIVE_ALT)
643  exit(0);
644  //if ( glutGetWindow() == 1 )
645  // exit(0); // Alt-F4 terminates the program
646  //else
647  //{
648  // int window_to_close = glutGetWindow();
649  // window_list[window_to_close] = nullptr; // Nullify window
650  // std::cout << "Window to close: " << window_to_close << '\n';
651  // glutSetWindow(1); // Reset current window to main window
652  // std::cout << "Current window is now: " << glutGetWindow() << '\n';
653  // glutDestroyWindow(window_to_close);
654  //}
655  //std::cout << "Pressed a key" << '\n';
656  //glutPostRedisplay();
657 }
658 
660 // * Alt-F4 closes the window and terminates the program.
661 // */
662 //void Window::special_key_pressed(int key, double, double)
663 //{
664 // if ( key == GLUT_KEY_F4 && glutGetModifiers() == GLUT_ACTIVE_ALT )
665 // exit(0); // Alt-F4 terminates the program
666 //}
667 
669  return key_mods;
670 }
671 
673  key_mods = mods;
674 }
675 
676 void Window::start_timer(int msec) {
677  glutTimerFunc(msec, sgl_timer_expired, glutGetWindow());
678 }
679 
680 // Derived classes add custom behavior
682 
683 
684 
685 /*****************************************************
686  * ObjectWindow code
687  *****************************************************/
688 
689 /*
690  * Constructor
691  * Creates a graphics window with a its left-top corner at (left, top) in
692  * screen coordinates. Its width is width, and its height is height. The viewport
693  * it represents extends from min_x to max_y horizontally and from min_y to max_y vertically.
694  */
695 ObjectWindow::ObjectWindow(const std::string& title,
696  int left, int top,
697  int width, int height,
698  double min_x, double max_x,
699  double min_y, double max_y):
700  Window(title, left, top, width, height,
701  min_x, max_x, min_y, max_y),
702  active_object(nullptr) {}
703 
704 ObjectWindow::ObjectWindow(const std::string& title,
705  int width, int height):
706  Window(title, width, height),
707  active_object(nullptr) {}
708 
709 ObjectWindow::ObjectWindow(const std::string& title,
710  double min_x, double max_x,
711  double min_y, double max_y):
712  Window(title, min_x, max_x, min_y, max_y),
713  active_object(nullptr) {}
714 
716 
717 
719  window_list[glutGetWindow()] = nullptr;
720  remove_all(); // Remove and delete all contained graphical objects
721  //object_list.clear();
722 }
723 
726 }
727 
729  for (auto& p : object_list)
730  p->paint();
732 }
733 
734 void ObjectWindow::mouse_pressed(double x, double y, MouseButton button) {
735  if (active_object) {
736  active_object->mouse_pressed(x, y, button);
737  repaint();
738  }
739  Window::mouse_pressed(x, y, button);
740 }
741 
742 void ObjectWindow::mouse_released(double x, double y,
743  MouseButton button) {
744  if (active_object) {
745  active_object->mouse_released(x, y, button);
746  repaint();
747  }
748  Window::mouse_released(x, y, button);
749 }
750 
751 void ObjectWindow::mouse_moved(double x, double y) {
752  GraphicalObject *prev_active = active_object;
753  active_object = hit(x, y);
754  if (prev_active != active_object) {
755  if (prev_active) {
756  prev_active->set_mouse_over(false);
758  }
759  if (active_object) {
760  active_object->set_mouse_over(true);
761  active_object->mouse_moved(x, y);
762  set_cursor(active_object->get_cursor());
763  }
764  repaint();
765  }
766 }
767 
768 void ObjectWindow::mouse_dragged(double x, double y) {
769  if (active_object) {
770  active_object->mouse_dragged(x, y);
771  repaint();
772  }
773 }
774 
775 void ObjectWindow::key_pressed(int key, double x, double y) {
776  if (active_object) {
777  active_object->key_pressed(key, x, y);
778  repaint();
779  }
780  Window::key_pressed(key, x, y);
781 }
782 
783 
784 // Add the given graphical object obj to the display list
786  //std::cout << "In add" << '\n';
787  //std::cout << static_cast<void *>(obj) << '\n';
788  //std::cout << static_cast<void *>(this) << '\n';
789  object_list.push_back(obj);
790  obj->set_window(this);
791 }
792 
793 
794 // Remove the given graphical object obj from the display list and
795 // deallocate the removed graphical object.
797  object_list.erase(std::remove(object_list.begin(), object_list.end(), obj), object_list.end());
798  //object_list.remove(obj);
799  if (active_object == obj)
800  active_object = nullptr;
801  delete obj;
802  repaint();
803 }
804 
805 // Remove all the graphical objects from the display list
806 // Frees up the memory allocated for the object
808  for (auto& p : object_list)
809  delete p;
810  object_list.clear();
811  active_object = nullptr;
812  repaint();
813 }
814 
815 // Return the first graphical object in the display list that is hit
816 // by the given point (x,y). If no objects in the list intersect the
817 // given point, return null.
818 GraphicalObject *ObjectWindow::hit(double x, double y) const {
819  for (auto p = object_list.rbegin(); p != object_list.rend(); p++)
820  if ((*p)->hit(x, y))
821  return *p;
822  return nullptr; // No object hit
823 }
824 
831 std::vector<GraphicalObject *>::iterator ObjectWindow::begin() {
832  return object_list.begin();
833 }
834 
841 std::vector<GraphicalObject *>::iterator ObjectWindow::end() {
842  return object_list.end();
843 }
844 
845 
846 /*****************************************************
847  * Pixmap code
848  *****************************************************/
849 
867 unsigned short Pixmap::get_short(std::ifstream& fin) {
868  // BMP format uses little-endian integer types
869  // get a 2-byte integer stored in little-endian form
870  char ic;
871  unsigned short ip;
872 
873  fin.get(ic);
874 
875  //first byte is little one
876  ip = ic;
877 
878  fin.get(ic);
879 
880  // or in high order byte
881  ip |= ((unsigned short)ic << 8);
882 
883  return ip;
884 }
885 
893 unsigned long Pixmap::get_long(std::ifstream& fin) {
894  //BMP format uses little-endian integer types
895  // get a 4-byte integer stored in little-endian form
896  unsigned long ip = 0;
897  char ic = 0;
898  unsigned char uc = ic;
899 
900  fin.get(ic);
901  ip = uc = ic;
902 
903  fin.get(ic);
904  uc = ic;
905  ip |=((unsigned long)uc << 8);
906 
907  fin.get(ic);
908  uc = ic;
909  ip |=((unsigned long)uc << 16);
910 
911  fin.get(ic);
912  uc = ic;
913  ip |=((unsigned long)uc << 24);
914 
915  return ip;
916 }
917 
925 bool Pixmap::power_of_2(int n) {
926  return n == 1 || n == 2 || n == 4 || n == 8 || n == 16
927  || n == 32 || n ==64 || n == 128 || n == 256
928  || n == 512 || n == 1024 || n == 2048 || n == 4096
929  || n == 8192 || n == 16384 || n == 32768
930  || n == 65536 || n == 131072 || n == 262144
931  || n == 524288 || n == 1048576 || n == 2097152
932  || n == 4194304 || n == 8388608 || n == 16777216;
933 }
934 
942 bool Pixmap::read_BMP_file(const char *fname) {
943  std::ifstream fin;
944 
945  bool result = false; // Unsuccessful by default
946 
947  // Read into memory an mRGB image from an uncompressed BMP file.
948  // return false on failure and true on success
949 
950  // open input file to read binary char's
951  fin.open(fname, std::ios::in|std::ios::binary);
952 
953  if ( !fin.good() ) // File opened successfully?
954  std::cout << " can't open file: " << fname << '\n';
955  else { // Continue if file was opened sucessfully
956  // First, load all the preliminary file information
957  fin.get(); // Read the file header information
958  fin.get(); //type: always 'BM'
959  get_long(fin); // file size
960  get_short(fin); // reserved, always 0
961  get_short(fin); // reserved, always 0
962  get_long(fin); // offset to image - unreliable
963  get_long(fin); // header size, always 40
964  unsigned long numCols = get_long(fin); // number of columns in image
965  unsigned long numRows = get_long(fin); // number of rows in image
966  get_short(fin); // number of planes, always 1
967  unsigned short bitsPerPixel = get_short(fin); // 8 or 24; allow 24 here
968  get_long(fin); // compression, must be 0 for uncompressed
969  get_long(fin); // total bytes in image
970  get_long(fin); // x pels, always 0
971  get_long(fin); // y pels, always 0
972  get_long(fin); // Number of LUT entries, 256 for 8 bit, otherwise 0
973  get_long(fin); // impColors, always 0
974 
975  if (bitsPerPixel != 24) // Error - must be a 24 bit uncompressed image
976  std::cout << "Not a 24 bit/pixelimage, or is compressed!\n";
977  else { // Bits per pixel OK
978  // Check for length of sides--must be a power of two
979  if (!power_of_2(numRows) || !power_of_2(numCols))
980  std::cout << "Length of sides must be powers of two\n";
981  else { // add bytes at end of each row so total # is a multiple of 4
982  // round up 3*numCols to next multiple of 4
983  int nBytesInRow = ((3 * numCols + 3)/4) * 4,
984  numPadBytes = nBytesInRow - 3 * numCols; // need this many
985 
986  // set class's data members
987  nRows = numRows;
988  nCols = numCols;
989 
990  //make space for array
991  pixel = new RGB[nRows * nCols];
992 
993  if ( !pixel ) // Check for proper memory allocation
994  std::cout << "Out of memory!\n";
995  else {
996  long count = 0;
997  for (int row = 0; row < nRows; row++) { // read pixel values
998  for (int col = 0; col < nCols; col++) {
999  char r, g, b;
1000  // Read three bytes ...
1001  fin.get(b);
1002  fin.get(g);
1003  fin.get(r);
1004  // ... and place the RGB values
1005  pixel[count].red = r;
1006  pixel[count].green = g;
1007  pixel[count].blue = b;
1008  count++;
1009  }
1010  // Skip pad bytes at row's end
1011  for(int k = 0 ; k < numPadBytes ; k++)
1012  fin.get();
1013  }
1014  // All went OK; can register success
1015  result = true;
1016  }
1017  }
1018  }
1019  fin.close();
1020  }
1021  return result;
1022 }
1023 
1031  bool result = false; // Unsuccessful by default
1032  // make a checkerboard patten
1033  nRows = nCols = 64;
1034  pixel = new RGB[3 * nRows * nCols];
1035 
1036  if (!pixel) { // Unable to allocate memory
1037  std::cout << "out of memory!\n";
1038  }
1039  else {
1040  long count = 0;
1041  for (int i = 0; i < nRows; i++) {
1042  for (int j = 0; j < nCols; j++) {
1043  unsigned char c = static_cast<unsigned char>((((i/8) + (j/8)) %2) * 255);
1044  pixel[count].red = c; // red
1045  pixel[count].green = c; // green
1046  pixel[count].blue = 0; // blue
1047  count++;
1048  }
1049  }
1050  result = true;
1051  }
1052  return result;
1053 }
1054 
1055 void Pixmap::set_texture(GLuint textureName) {
1056  glBindTexture(GL_TEXTURE_2D, textureName);
1057  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1058  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1059  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, nCols, nRows, 0, GL_RGB,
1060  GL_UNSIGNED_BYTE, pixel);
1061 }
1062 
1063 
1064 
1065 
1066 /*****************************************************
1067  * BitmapObject code
1068  *****************************************************/
1069 
1081 BitmapObject::BitmapObject(const char *filename, double x, double y,
1082  double width, double height): GraphicalObject(x, y, width, height) {
1083  pix.read_BMP_file(filename);
1084  glGenTextures(1, &texture_id);
1085  pix.set_texture(texture_id); // create texture
1086 }
1087 
1091 void BitmapObject::paint() const {
1092  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1093  glEnable(GL_TEXTURE_2D);
1094  glBindTexture(GL_TEXTURE_2D, texture_id); // top face: Ennis
1095  glBegin(GL_QUADS);
1096  glTexCoord2f(0.0, 0.0); glVertex2d(left, bottom);
1097  glTexCoord2f(1.0, 0.0); glVertex2d(left + width, bottom);
1098  glTexCoord2f(1.0, 1.0); glVertex2d(left + width, bottom + height);
1099  glTexCoord2f(0.0, 1.0); glVertex2d(left, bottom + height);
1100  glEnd();
1101  glDisable(GL_TEXTURE_2D);
1102 }
1103 
1104 /*****************************************************
1105  * CompositeObject code
1106  *****************************************************/
1107 
1113  GraphicalObject(0.0, 0.0, 0.0, 0.0),
1114  objects(0) {}
1115 
1116 /*
1117  * The destructor frees up all contained objects.
1118  */
1119 CompositeObject::~CompositeObject() {
1120  for (auto& obj : objects)
1121  delete obj;
1122 }
1123 
1124 
1131  // Debugging: Draw container's bounding box
1132  set_color(BLUE);
1134  // Draw each object in this container
1135  for (auto& obj : objects)
1136  obj->paint();
1137 }
1138 
1144 void CompositeObject::move_to(double x, double y) {
1145  double old_left = left, old_bottom = bottom;
1147  double dx = left - old_left, dy = bottom - old_bottom;
1148  for (auto& obj : objects) {
1149  obj->move_to(obj->get_left() + dx, obj->get_bottom() + dy);
1150  }
1151 }
1152 
1162  // Adjust this container's size, if necessary
1163  // to accommodate the new element.
1164  if (objects.size() == 0) { // Add first element
1165  left = obj->get_left();
1166  bottom = obj->get_bottom();
1167  width = obj->get_width();
1168  height = obj->get_height();
1169  }
1170  else { // Contains at least one element
1171  double new_left = (obj->get_left() < left)? obj->get_left() : left,
1172  new_bottom = (obj->get_bottom() < bottom)? obj->get_bottom() : bottom,
1173  right = left + width,
1174  obj_right = obj->get_left() + obj->get_width(),
1175  top = bottom + height,
1176  obj_top = obj->get_bottom() + obj->get_height();
1177  left = new_left;
1178  bottom = new_bottom;
1179  width = (obj_right > right)? obj_right - left : right - left;
1180  height = (obj_top > top)? obj_top - bottom : top - bottom;
1181  }
1182 
1183  // Place object in this container
1184  objects.push_back(obj);
1185 }
1186 
1187 
1188 
1189 /*****************************************************
1190  * OGLWindow code
1191  *****************************************************/
1192 
1204 OGLWindow::OGLWindow(const std::string& title, int left, int top,
1205  int width, int height):
1206  Window(title, left, top, width, height) {}
1207 
1212 OGLWindow::OGLWindow(const std::string& title):
1213  Window(title, 0.0, 0.0, 0.0, 0.0) {}
1218 
1224 
1230 
1231 
1232 /*****************************************************
1233  * Seven segment display code
1234  *****************************************************/
1235 
1236 // Older, vector-based version
1237 
1238 //class SevenSegmentDigit
1239 //{
1240 //protected:
1241 // int current_value;
1242 //
1243 // Color color;
1244 // double x, y; // (x,y) coordinates of lower-left corner of the LED
1245 // double height; // The height of the LED
1246 //
1247 // // Draw the segments:
1248 // // +--- a ---+
1249 // // | |
1250 // // f b
1251 // // | |
1252 // // +--- g ---+
1253 // // | |
1254 // // e c
1255 // // | |
1256 // // +--- d ---+
1257 //
1258 // vector<Point> segment_a,
1259 // segment_b,
1260 // segment_c,
1261 // segment_d,
1262 // segment_e,
1263 // segment_f,
1264 // segment_g;
1265 //
1266 //
1267 // void update_segment_locations()
1268 // {
1269 // double width = height/2.0,
1270 // max_x = x + width,
1271 // max_y = y + height,
1272 // mid_y = y + width,
1273 // mid_left_x = x + 0.1*width,
1274 // mid_right_x = x + 0.9 * width,
1275 // top_left_x = x + 0.2 * width,
1276 // bottom_right_x = x + 0.8 * width,
1277 // offset = 0.12 * width,
1278 // half_offset = 0.5 * offset,
1279 // inc = 0.3 * offset;
1280 //
1281 //
1282 // // Clear all the segments
1283 // segment_a.clear();
1284 // segment_b.clear();
1285 // segment_c.clear();
1286 // segment_d.clear();
1287 // segment_e.clear();
1288 // segment_f.clear();
1289 // segment_g.clear();
1290 //
1291 // // Make segment a
1292 // segment_a.push_back(Point(top_left_x, max_y));
1293 // segment_a.push_back(Point(max_x, max_y));
1294 // segment_a.push_back(Point(max_x - offset, max_y - offset));
1295 // segment_a.push_back(Point(top_left_x + offset, max_y - offset));
1296 //
1297 // // Make segment b
1298 // segment_b.push_back(Point(max_x, max_y - inc));
1299 // segment_b.push_back(Point(mid_right_x, mid_y + inc));
1300 // segment_b.push_back(Point(mid_right_x - offset, mid_y + offset - inc));
1301 // segment_b.push_back(Point(max_x - offset, max_y - offset - inc));
1302 //
1303 // // Make segment c
1304 // segment_c.push_back(Point(mid_right_x, mid_y - inc));
1305 // segment_c.push_back(Point(bottom_right_x, y + inc));
1306 // segment_c.push_back(Point(bottom_right_x - offset, y + offset + inc));
1307 // segment_c.push_back(Point(mid_right_x - offset, mid_y - offset + inc));
1308 //
1309 // // Make segment d
1310 // segment_d.push_back(Point(x, y));
1311 // segment_d.push_back(Point(bottom_right_x, y));
1312 // segment_d.push_back(Point(bottom_right_x - offset, y + offset));
1313 // segment_d.push_back(Point(x + offset, y + offset));
1314 //
1315 // // Make segment e
1316 // segment_e.push_back(Point(x, y + inc));
1317 // segment_e.push_back(Point(mid_left_x, mid_y - inc));
1318 // segment_e.push_back(Point(mid_left_x + offset, mid_y - offset + inc));
1319 // segment_e.push_back(Point(x + offset, y + offset + inc));
1320 //
1321 // // Make segment f
1322 // segment_f.push_back(Point(mid_left_x, mid_y + inc));
1323 // segment_f.push_back(Point(top_left_x, max_y - inc));
1324 // segment_f.push_back(Point(top_left_x + offset, max_y - offset - inc));
1325 // segment_f.push_back(Point(mid_left_x + offset, mid_y + offset - inc));
1326 //
1327 // // Make segment g
1328 // segment_g.push_back(Point(mid_left_x, mid_y));
1329 //
1330 // segment_g.push_back(Point(mid_left_x + offset, mid_y + half_offset));
1331 // segment_g.push_back(Point(mid_right_x - offset, mid_y + half_offset));
1332 //
1333 // segment_g.push_back(Point(mid_right_x, mid_y));
1334 //
1335 // segment_g.push_back(Point(mid_right_x - offset, mid_y - half_offset));
1336 // segment_g.push_back(Point(mid_left_x + offset, mid_y - half_offset));
1337 // }
1338 //
1339 //public:
1340 // SevenSegmentDigit(Color color, double x, double y, double height):
1341 // current_value(0), color(color), x(x), y(y), height(height)
1342 // {
1343 // update_segment_locations();
1344 // }
1345 //
1346 // double get_x() const
1347 // {
1348 // return x;
1349 // }
1350 //
1351 // double get_y() const
1352 // {
1353 // return y;
1354 // }
1355 //
1356 // double get_height() const
1357 // {
1358 // return height;
1359 // }
1360 //
1361 // void paint() const
1362 // {
1363 // set_color(color);
1364 //
1365 // switch ( current_value )
1366 // {
1367 // case 0:
1368 // fill_polygon(segment_a);
1369 // fill_polygon(segment_b);
1370 // fill_polygon(segment_c);
1371 // fill_polygon(segment_d);
1372 // fill_polygon(segment_e);
1373 // fill_polygon(segment_f);
1374 // break;
1375 // case 1:
1376 // fill_polygon(segment_b);
1377 // fill_polygon(segment_c);
1378 // break;
1379 // case 2:
1380 // fill_polygon(segment_a);
1381 // fill_polygon(segment_b);
1382 // fill_polygon(segment_d);
1383 // fill_polygon(segment_e);
1384 // fill_polygon(segment_g);
1385 // break;
1386 // case 3:
1387 // fill_polygon(segment_a);
1388 // fill_polygon(segment_b);
1389 // fill_polygon(segment_c);
1390 // fill_polygon(segment_d);
1391 // fill_polygon(segment_g);
1392 // break;
1393 // case 4:
1394 // fill_polygon(segment_b);
1395 // fill_polygon(segment_c);
1396 // fill_polygon(segment_f);
1397 // fill_polygon(segment_g);
1398 // break;
1399 // case 5:
1400 // fill_polygon(segment_a);
1401 // fill_polygon(segment_c);
1402 // fill_polygon(segment_d);
1403 // fill_polygon(segment_f);
1404 // fill_polygon(segment_g);
1405 // break;
1406 // case 6:
1407 // fill_polygon(segment_a);
1408 // fill_polygon(segment_c);
1409 // fill_polygon(segment_d);
1410 // fill_polygon(segment_e);
1411 // fill_polygon(segment_f);
1412 // fill_polygon(segment_g);
1413 // break;
1414 // case 7:
1415 // fill_polygon(segment_a);
1416 // fill_polygon(segment_b);
1417 // fill_polygon(segment_c);
1418 // break;
1419 // case 8:
1420 // fill_polygon(segment_a);
1421 // fill_polygon(segment_b);
1422 // fill_polygon(segment_c);
1423 // fill_polygon(segment_d);
1424 // fill_polygon(segment_e);
1425 // fill_polygon(segment_f);
1426 // fill_polygon(segment_g);
1427 // break;
1428 // case 9:
1429 // fill_polygon(segment_a);
1430 // fill_polygon(segment_b);
1431 // fill_polygon(segment_c);
1432 // fill_polygon(segment_d);
1433 // fill_polygon(segment_f);
1434 // fill_polygon(segment_g);
1435 // break;
1436 // }
1437 // }
1438 //
1439 // void set_value(int value)
1440 // {
1441 // current_value = value % 10;
1442 // }
1443 //
1444 // int get_value() const
1445 // {
1446 // return current_value;
1447 // }
1448 //
1449 // void increment()
1450 // {
1451 // current_value = (current_value + 1) % 10;
1452 // }
1453 //
1454 // void decrement()
1455 // {
1456 // current_value = (current_value == 0)? 9 : current_value - 1;
1457 // }
1458 //
1459 // void resize(double inc)
1460 // {
1461 // height += inc;
1462 // update_segment_locations();
1463 // }
1464 //
1465 // void move(double x, double y)
1466 // {
1467 // this->x = x;
1468 // this->y = y;
1469 // update_segment_locations();
1470 // }
1471 //};
1472 
1473 
1474 
1476  double width = height/2.0,
1477  max_x = x + width,
1478  max_y = y + height,
1479  mid_y = y + width,
1480  mid_left_x = x + 0.1*width,
1481  mid_right_x = x + 0.9 * width,
1482  top_left_x = x + 0.2 * width,
1483  bottom_right_x = x + 0.8 * width,
1484  offset = 0.14 * width,
1485  half_offset = 0.5 * offset,
1486  inc = 0.3 * offset;
1487 
1488  // Make segment a
1489  segment_a[0].x = top_left_x; segment_a[0].y = max_y;
1490  segment_a[1].x = max_x; segment_a[1].y = max_y;
1491  segment_a[2].x = max_x - offset; segment_a[2].y = max_y - offset;
1492  segment_a[3].x = top_left_x + offset; segment_a[3].y = max_y - offset;
1493 
1494  // Make segment b
1495  segment_b[0].x = max_x; segment_b[0].y = max_y - inc;
1496  segment_b[1].x = mid_right_x; segment_b[1].y = mid_y + inc;
1497  segment_b[2].x = mid_right_x - offset; segment_b[2].y = mid_y + offset - inc;
1498  segment_b[3].x = max_x - offset; segment_b[3].y = max_y - offset - inc;
1499 
1500  // Make segment c
1501  segment_c[0].x = mid_right_x; segment_c[0].y = mid_y - inc;
1502  segment_c[1].x = bottom_right_x; segment_c[1].y = y + inc;
1503  segment_c[2].x = bottom_right_x - offset; segment_c[2].y = y + offset + inc;
1504  segment_c[3].x = mid_right_x - offset; segment_c[3].y = mid_y - offset + inc;
1505 
1506  // Make segment d
1507  segment_d[0].x = x; segment_d[0].y = y;
1508  segment_d[1].x = bottom_right_x; segment_d[1].y = y;
1509  segment_d[2].x = bottom_right_x - offset; segment_d[2].y = y + offset;
1510  segment_d[3].x = x + offset; segment_d[3].y = y + offset;
1511 
1512  // Make segment e
1513  segment_e[0].x = x; segment_e[0].y = y + inc;
1514  segment_e[1].x = mid_left_x; segment_e[1].y = mid_y - inc;
1515  segment_e[2].x = mid_left_x + offset; segment_e[2].y = mid_y - offset + inc;
1516  segment_e[3].x = x + offset; segment_e[3].y = y + offset + inc;
1517 
1518  // Make segment f
1519  segment_f[0].x = mid_left_x; segment_f[0].y = mid_y + inc;
1520  segment_f[1].x = top_left_x; segment_f[1].y = max_y - inc;
1521  segment_f[2].x = top_left_x + offset; segment_f[2].y = max_y - offset - inc;
1522  segment_f[3].x = mid_left_x + offset; segment_f[3].y = mid_y + offset - inc;
1523 
1524  // Make segment g
1525  segment_g[0].x = mid_left_x; segment_g[0].y = mid_y;
1526 
1527  segment_g[1].x = mid_left_x + offset; segment_g[1].y = mid_y + half_offset;
1528  segment_g[2].x = mid_right_x - offset; segment_g[2].y = mid_y + half_offset;
1529 
1530  segment_g[3].x = mid_right_x; segment_g[3].y = mid_y;
1531 
1532  segment_g[4].x = mid_right_x - offset; segment_g[4].y = mid_y - half_offset;
1533  segment_g[5].x = mid_left_x + offset; segment_g[5].y = mid_y - half_offset;
1534 }
1535 
1543 SevenSegmentDigit::SevenSegmentDigit(Color color, double x, double y, double height):
1544  current_value(0), color(color), x(x), y(y), height(height) {
1546 }
1547 
1553  return x;
1554 }
1555 
1561  return y;
1562 }
1563 
1569  return height;
1570 }
1571 
1576  set_color(color);
1577 
1578  switch (current_value) {
1579  case 0:
1580  fill_polygon(segment_a, 4);
1581  fill_polygon(segment_b, 4);
1582  fill_polygon(segment_c, 4);
1583  fill_polygon(segment_d, 4);
1584  fill_polygon(segment_e, 4);
1585  fill_polygon(segment_f, 4);
1586  break;
1587  case 1:
1588  fill_polygon(segment_b, 4);
1589  fill_polygon(segment_c, 4);
1590  break;
1591  case 2:
1592  fill_polygon(segment_a, 4);
1593  fill_polygon(segment_b, 4);
1594  fill_polygon(segment_d, 4);
1595  fill_polygon(segment_e, 4);
1596  fill_polygon(segment_g, 6);
1597  break;
1598  case 3:
1599  fill_polygon(segment_a, 4);
1600  fill_polygon(segment_b, 4);
1601  fill_polygon(segment_c, 4);
1602  fill_polygon(segment_d, 4);
1603  fill_polygon(segment_g, 6);
1604  break;
1605  case 4:
1606  fill_polygon(segment_b, 4);
1607  fill_polygon(segment_c, 4);
1608  fill_polygon(segment_f, 4);
1609  fill_polygon(segment_g, 6);
1610  break;
1611  case 5:
1612  fill_polygon(segment_a, 4);
1613  fill_polygon(segment_c, 4);
1614  fill_polygon(segment_d, 4);
1615  fill_polygon(segment_f, 4);
1616  fill_polygon(segment_g, 6);
1617  break;
1618  case 6:
1619  fill_polygon(segment_a, 4);
1620  fill_polygon(segment_c, 4);
1621  fill_polygon(segment_d, 4);
1622  fill_polygon(segment_e, 4);
1623  fill_polygon(segment_f, 4);
1624  fill_polygon(segment_g, 6);
1625  break;
1626  case 7:
1627  fill_polygon(segment_a, 4);
1628  fill_polygon(segment_b, 4);
1629  fill_polygon(segment_c, 4);
1630  break;
1631  case 8:
1632  fill_polygon(segment_a, 4);
1633  fill_polygon(segment_b, 4);
1634  fill_polygon(segment_c, 4);
1635  fill_polygon(segment_d, 4);
1636  fill_polygon(segment_e, 4);
1637  fill_polygon(segment_f, 4);
1638  fill_polygon(segment_g, 6);
1639  break;
1640  case 9:
1641  fill_polygon(segment_a, 4);
1642  fill_polygon(segment_b, 4);
1643  fill_polygon(segment_c, 4);
1644  fill_polygon(segment_d, 4);
1645  fill_polygon(segment_f, 4);
1646  fill_polygon(segment_g, 6);
1647  break;
1648  }
1649 }
1650 
1658  current_value = value % 10;
1659 }
1660 
1666  return current_value;
1667 }
1668 
1674  current_value = (current_value + 1) % 10;
1675 }
1676 
1682  current_value = (current_value == 0)? 9 : current_value - 1;
1683 }
1684 
1691 void SevenSegmentDigit::resize(double inc) {
1692  height += inc;
1694 }
1695 
1703 void SevenSegmentDigit::move_to(double x, double y) {
1704  this->x = x;
1705  this->y = y;
1707 }
1708 
1709 
1710 
1719 DisplayDigit::DisplayDigit(Color color, double x, double y, double height):
1720  GraphicalObject(x, y, height/2.0, height), led(color, x, y, height) {
1721  // Nothing to do here
1722 }
1723 
1725 void DisplayDigit::paint() const {
1726  /*set_color(WHITE);
1727  draw_rectangle(left, bottom, width, height);*/
1728  led.paint();
1729 }
1730 
1731 
1738 void DisplayDigit::set_value(int value) {
1739  led.set_value(value);
1740 }
1741 
1747  return led.get_value();
1748 }
1749 
1750 
1756  led.increment();
1757 }
1758 
1764  led.decrement();
1765 }
1766 
1773 void DisplayDigit::resize(double inc) {
1774  led.resize(inc);
1775  width += inc/2.0;
1776  height += inc;
1777 }
1778 
1786 void DisplayDigit::mouse_dragged(double x, double y) {
1788  led.move_to(left, bottom);
1789 }
1790 
1791 
1800 DoubleDigit::DoubleDigit(Color color, double x, double y, double height):
1801  GraphicalObject(x, y, height + 2, height),
1802  tens(color, x, y, height),
1803  ones(color, x + height/2.0 + 2, y, height),
1804  leading_zero(true), visible(true) {
1805  // Nothing to do here
1806 }
1807 
1809 void DoubleDigit::paint() const {
1810  /*set_color(WHITE);
1811  draw_rectangle(left, bottom, width, height);*/
1812  if ( visible )
1813  {
1814  if ( leading_zero || tens.get_value() != 0 )
1815  tens.paint();
1816  ones.paint();
1817  }
1818 }
1819 
1826 void DoubleDigit::set_value(int value) {
1827  tens.set_value(value / 10);
1828  ones.set_value(value % 10);
1829 }
1830 
1836  return 10*tens.get_value() + ones.get_value();
1837 }
1838 
1844  if (ones.get_value() == 9)
1845  tens.increment();
1846  ones.increment();
1847 }
1848 
1854  if (ones.get_value() == 0)
1855  tens.decrement();
1856  ones.decrement();
1857 }
1858 
1865 void DoubleDigit::resize(double inc) {
1866  tens.resize(inc);
1867  ones.resize(inc);
1868  ones.move_to(tens.get_x() + tens.get_height()/2.0 + 2, ones.get_y());
1869  width += inc/2.0;
1870  height += inc;
1871 }
1872 
1882 void DoubleDigit::mouse_dragged(double x, double y) {
1884  tens.move_to(left, bottom);
1885  ones.move_to(left + height/2.0 + 2.0, bottom);
1886 }
1887 
1895  leading_zero = flag;
1896 }
1897 
1904 void DoubleDigit::set_visible(bool flag) {
1905  visible = flag;
1906 }
1907 
1908 
1909 
1920 Multidigit::Multidigit(int n, Color color, double x, double y, double height):
1921  GraphicalObject(x, y, n*height/2.0, height),
1922  digits(n, SevenSegmentDigit(color, x, y, height)),
1923  //tens(color, x, y, height),
1924  //ones(color, x + height/2.0 + 2, y, height),
1925  leading_zeros(true), visible(true) {
1926  double offset = height/2.0;
1927  for (int i = 0; i < n; i++)
1928  digits[i].move_to(x + i*offset, y);
1929 }
1930 
1932 void Multidigit::paint() const {
1933  /*
1934  set_color(BLACK);
1935  draw_rectangle(left, bottom, width, height);
1936  */
1937  if (visible) {
1938  int n = digits.size();
1939  int i = 0;
1940  if (!leading_zeros) // Skip leading zeros
1941  while (i < n - 1 && digits[i].get_value() == 0)
1942  i++;
1943  while (i < n) {
1944  digits[i].paint();
1945  i++;
1946  }
1947  }
1948 }
1949 
1955 void Multidigit::set_value(int value) {
1956  const int divisor = 10;
1957  int n = digits.size();
1958  for (int i = 0; i < n; i++) {
1959  digits[n - i - 1].set_value(value % divisor);
1960  value /= divisor;
1961  }
1962 }
1963 
1969  int multiplier = 1;
1970  int result = 0;
1971  int n = digits.size();
1972  for (int i = n - 1; i >= 0; i--) {
1973  result += digits[i].get_value()*multiplier;
1974  multiplier *= 10;
1975  }
1976  return result;
1977 }
1978 
1979 
1980 void Multidigit::increment_helper(int n) {
1981  if (n >= 0) {
1982  digits[n].increment();
1983  if (digits[n].get_value() == 0)
1984  increment_helper(n - 1);
1985  }
1986 }
1987 
1988 void Multidigit::decrement_helper(int n) {
1989  if (n >= 0) {
1990  digits[n].decrement();
1991  if (digits[n].get_value() == 9)
1992  decrement_helper(n - 1);
1993  }
1994 }
1995 
2001  increment_helper(digits.size() - 1);
2002 }
2003 
2009  decrement_helper(digits.size() - 1);
2010 }
2011 
2018 void Multidigit::resize(double inc) {
2019  int n = digits.size();
2020  digits[0].resize(inc);
2021  double offset = digits[0].get_height()/2.0;
2022  for (int i = 1; i < n; i++) {
2023  digits[i].resize(inc);
2024  digits[i].move_to(digits[0].get_x() + i*offset, digits[0].get_y());
2025  }
2026  height += inc;
2027  width = n*offset;
2028 }
2029 
2039 void Multidigit::mouse_dragged(double x, double y) {
2041  int n = digits.size();
2042  double offset = height/2.0;
2043  for (int i = 0; i < n; i++)
2044  digits[i].move_to(left + i*offset, bottom);
2045 }
2046 
2059 void Multidigit::move_to(double x, double y) {
2060  double old_left = left,
2061  old_bottom = bottom;
2063  double dx = left - old_left,
2064  dy = bottom - old_bottom;
2065  int n = digits.size();
2066  for (int i = 0; i < n; i++)
2067  digits[i].move_to(digits[i].get_x() + dx,
2068  digits[i].get_y() + dy);
2069 }
2070 
2078  leading_zeros = flag;
2079 }
2080 
2087 void Multidigit::set_visible(bool flag) {
2088  visible = flag;
2089 }
2090 
2091 
2092 
2100  const SevenSegmentDigit& right_tens) const {
2101  double width = height/2.0,
2102  rect_width = width/8.0,
2103  x = (left_ones.get_x() + width + right_tens.get_x())/2.0 - rect_width/2.0;
2104  fill_rectangle(x, bottom + height/3.0, rect_width, rect_width);
2105  fill_rectangle(x, bottom + 2.0*height/3.0, rect_width, rect_width);
2106 }
2107 
2108 
2115  if ( hours_tens.get_value() > 0 ) // Need to display tens of hours?
2116  hours_tens.paint(); // Draw the hours 10s digit
2117  if (seconds >= 3600) { // Need to display hours?
2118  hours_ones.paint();
2119  draw_separator(hours_ones, minutes_tens);
2120  }
2121 
2122  if (seconds >= 3600 || minutes_tens.get_value() != 0) // Need to display minutes?
2123  minutes_tens.paint(); // Draw the minutes 10s digit
2124  if (seconds >= 3600 || minutes_ones.get_value() != 0 || minutes_tens.get_value() != 0) {
2125  minutes_ones.paint(); // Draw the minutes 1s digit
2126  draw_separator(minutes_ones, seconds_tens);
2127  }
2128 
2129  // Draw the seconds digits
2130  if (seconds >= 60 || seconds_tens.get_value() != 0) // Need to display 10s of seconds?
2131  seconds_tens.paint();
2132  seconds_ones.paint(); // Always display ones of seconds
2133 
2134 }
2135 
2144 TimeDisplay::TimeDisplay(Color color, double x, double y, int height):
2145  GraphicalObject(x, y, 6*height/2.0 + 2*height/4.0, height),
2146  hours_tens(color, x, y, height),
2147  hours_ones(color, x + height/2.0, y, height),
2148  minutes_tens(color, x + 2*height/2.0 + height/4.0, y, height),
2149  minutes_ones(color, x + 3*height/2.0 + height/4.0, y, height),
2150  seconds_tens(color, x + 4*height/2.0 + 2*height/4.0, y, height),
2151  seconds_ones(color, x + 5*height/2.0 + 2*height/4.0, y, height),
2152  seconds(0), leading_units(true), visible(true) {}
2153 
2154 
2155 
2159 void TimeDisplay::paint() const {
2160  set_color(BLUE);
2162  if (visible) {
2163  if (leading_units) {
2164  // Draw the hours digits
2165  hours_tens.paint();
2166  hours_ones.paint();
2167 
2168  // Draw the hours-minutes colon separator
2170 
2171  // Draw the minutes digits
2172  minutes_tens.paint();
2173  minutes_ones.paint();
2174 
2175  // Draw the minutes-seconds colon separator
2177 
2178  // Draw the seconds digits
2179  seconds_tens.paint();
2180  seconds_ones.paint();
2181  }
2182  else
2184  }
2185 }
2186 
2193 {
2194  sec %= 360000; // Upper limit is 99:59:59 (359999 secs)
2195  sec = (sec < 0)? 0 : sec;
2196  if (sec != seconds) {
2197  // Compute hours, minutes, and seconds
2198  seconds = sec;
2199  int hours, minutes;
2200  hours = sec/3600;
2201  sec %= 3600;
2202  minutes = sec/60;
2203  sec %= 60;
2204 
2205  // Compute digit values
2206  hours_tens.set_value(hours/10);
2207  hours_ones.set_value(hours%10);
2208  minutes_tens.set_value(minutes/10);
2209  minutes_ones.set_value(minutes%10);
2210  seconds_tens.set_value(sec/10);
2211  seconds_ones.set_value(sec%10);
2212  }
2213 }
2214 
2220  return seconds;
2221 }
2222 
2228  set_value(get_value() + 1);
2229 }
2230 
2236  set_value(get_value() - 1);
2237 }
2238 
2245 void TimeDisplay::resize(double inc) {
2246  height += inc;
2247  width = 6*height/2.0 + height/2.0;
2248 
2249  hours_tens.resize(inc);
2250  hours_ones.resize(inc);
2251  minutes_tens.resize(inc);
2252  minutes_ones.resize(inc);
2253  seconds_tens.resize(inc);
2254  seconds_ones.resize(inc);
2255 
2256  double width = height/2.0,
2257  offset = height/4.0;
2259  hours_ones.move_to(left + width, bottom);
2260  minutes_tens.move_to(left + 2*width + offset, bottom);
2261  minutes_ones.move_to(left + 3*width + offset, bottom);
2262  seconds_tens.move_to(left + 4*width + 2.0*offset, bottom);
2263  seconds_ones.move_to(left + 5*width + 2.0*offset, bottom);
2264 }
2265 
2275 void TimeDisplay::mouse_dragged(double x, double y) {
2277  double width = height/2.0,
2278  offset = height/4.0;
2280  hours_ones.move_to(left + width, bottom);
2281  minutes_tens.move_to(left + 2*width + offset, bottom);
2282  minutes_ones.move_to(left + 3*width + offset, bottom);
2283  seconds_tens.move_to(left + 4*width + 2.0*offset, bottom);
2284  seconds_ones.move_to(left + 5*width + 2.0*offset, bottom);
2285 }
2286 
2296 void TimeDisplay::move_to(double x, double y) {
2298  double width = height/2.0,
2299  offset = height/4.0;
2301  hours_ones.move_to(left + width, bottom);
2302  minutes_tens.move_to(left + 2*width + offset, bottom);
2303  minutes_ones.move_to(left + 3*width + offset, bottom);
2304  seconds_tens.move_to(left + 4*width + 2.0*offset, bottom);
2305  seconds_ones.move_to(left + 5*width + 2.0*offset, bottom);
2306 }
2307 
2308 
2316  leading_units = flag;
2317 }
2318 
2325 void TimeDisplay::set_visible(bool flag) {
2326  visible = flag;
2327 }
2328 
2329 
2330 
2331 /*****************************************************
2332  * Graphical object code
2333  *****************************************************/
2334 
2335 
2336 // Constructor initializes the bounding box of the graphical object and
2337 // assigns a unique ID number to the object.
2338 GraphicalObject::GraphicalObject(double lf, double bm,
2339  double wd, double ht):
2340  window(0), left(lf), bottom(bm),
2341  width(wd), height(ht),
2342  cursor(CursorShape::Crosshair),
2343  mouse_over(false), id(id_source++) {
2344  std::cout << "Making a graphical object #" << id << '\n';;
2345  //std::cout << "left = " << left << ", bottom = " << bottom << '\n';
2346 }
2347 
2348 // Copy constructor makes a new graphical object with the same
2349 // characteristics except it has a unique ID
2351  left(go.left), bottom(go.bottom),
2352  width(go.width), height(go.height),
2353  cursor(CursorShape::Crosshair),
2354  mouse_over(false), id(id_source++) {}
2355 
2356 // Assignment operator copies all the graphical object
2357 // characteristics but does not affect the object's ID
2358 GraphicalObject& GraphicalObject::operator=
2359  (const GraphicalObject &go) {
2360  left = go.left;
2361  bottom = go.bottom;
2362  width = go.width;
2363  height = go.height;
2364  cursor = go.cursor;
2365  return *this;
2366 }
2367 
2368 // Destructor currently does nothing
2370  std::cout << "Destroying graphical object #" << id << '\n';
2371 }
2372 
2373 
2374 
2376  return left;
2377 }
2378 
2380  return bottom;
2381 }
2382 
2384  return width;
2385 }
2386 
2388  return height;
2389 }
2390 
2402 void GraphicalObject::set(double x, double y,
2403  double width, double height) {
2404  left = x;
2405  bottom = y;
2406  this->width = width;
2407  this->height = height;
2408 }
2409 
2410 
2411 
2412 // Determines if the point (x,y) falls within the bounding box of this
2413 // graphical object?
2414 bool GraphicalObject::hit(double x, double y) {
2415  if (x >= left && x <= left + width
2416  && y >= bottom && y <= bottom + height) {
2417  x_hit_offset = x - left;
2418  y_hit_offset = y - bottom;
2419  return true;
2420  }
2421  return false;
2422 }
2423 
2435 void GraphicalObject::mouse_dragged(double x, double y) {
2436  //left = x - x_hit_offset;
2437  //bottom = y - y_hit_offset;
2438  move_to(x - x_hit_offset, y - y_hit_offset);
2439 }
2440 
2441 void GraphicalObject::move_to(double x, double y) {
2442  left = x;
2443  bottom = y;
2444 }
2445 
2447  mouse_over = flag;
2448 }
2449 
2450 
2464 {}
2465 
2479 {}
2480 
2491 void GraphicalObject::mouse_moved(double, double)
2492 {}
2493 
2494 
2508 void GraphicalObject::key_pressed(int, double, double)
2509 {}
2510 
2511 
2512 
2514  Window *previous = window;
2515  window = win;
2516  return previous;
2517 }
2518 
2520  return window;
2521 }
2522 
2529  CursorShape prev_cursor = this->cursor;
2530  this->cursor = cursor;
2531  return prev_cursor;
2532 }
2533 
2541  return cursor;
2542 }
2543 
2544 
2545 
2546 unsigned GraphicalObject::id_source = 0;
2547 
2548 
2549 /*****************************************************
2550  * Popup menu code
2551  *****************************************************/
2552 
2553 static PopupMenu *current_popup_menu = nullptr;
2554 
2556  (items[n].code)();
2557 }
2558 
2560  current_popup_menu->execute_handler(option);
2561 }
2562 
2564  index = glutCreateMenu(PopupMenu::process_menu_events);
2565  current_popup_menu = this;
2566  glutAttachMenu(GLUT_RIGHT_BUTTON);
2567 }
2568 
2570 
2571 void PopupMenu::add_menu_item(const std::string& item, MenuItemFunction f) {
2572  glutAddMenuEntry(item.c_str(), items.size());
2573  items.push_back(MenuItem(item, f));
2574 }
2575 
2576 void PopupMenu::replace_menu_item(const std::string& old_name,
2577  const std::string& new_name,
2578  //WindowCallback func) {
2579  MenuItemFunction func) {
2580  int num_items = items.size();
2581  MenuItem new_item(new_name, func);
2582  for (int i = 0; i < num_items; i++)
2583  if (old_name == items[i].name) {
2584  items[i] = new_item;
2585  glutChangeToMenuEntry(i + 1, new_name.c_str(), i);
2586  return;
2587  }
2588  //std::cout << "replace_menu_item unimplemented at this time" << '\n';
2589 }
2590 
2591 
2592 void PopupMenu::remove_menu_item(const std::string& /* item */) {
2593  std::cout << "remove_menu_item unimplemented at this time\n";
2594  // Find index of current . . .
2595 }
2596 
2602  current_popup_menu = this;
2603  glutSetMenu(index);
2604  glutAttachMenu(GLUT_RIGHT_BUTTON);
2605 }
2606 
2607 
2608 
2609 
2610 /********************************************************
2611  * Global drawing functions
2612  ********************************************************/
2613 
2614 /*
2615  * set_color
2616  * Sets the current drawing color to the RGB values specified
2617  * by red, green, and blue.
2618  */
2619 void set_color(const Color& color) {
2620  glColor3d(color.red, color.green, color.blue);
2621 }
2622 
2623 void set_color(double r, double g, double b) {
2624  glColor3d(r, g, b);
2625 }
2626 
2627 void set_line_width(double width) {
2628  glLineWidth(static_cast<GLfloat>(width));
2629 }
2630 
2639 bool intersect(const GraphicalObject& obj1,
2640  const GraphicalObject& obj2) {
2641  double min_x_1 = obj1.get_left(),
2642  max_x_1 = min_x_1 + obj1.get_width(),
2643  min_y_1 = obj1.get_bottom(),
2644  max_y_1 = min_y_1 + obj1.get_height(),
2645 
2646  min_x_2 = obj2.get_left(),
2647  max_x_2 = min_x_2 + obj2.get_width(),
2648  min_y_2 = obj2.get_bottom(),
2649  max_y_2 = min_y_2 + obj2.get_height();
2650 
2651  return min_x_2 < max_x_1
2652  && max_x_2 > min_x_1
2653  && max_y_2 > min_y_1
2654  && min_y_2 < max_y_1;
2655 }
2656 
2657 
2658 /*
2659  * draw_point
2660  * Draws a point in the current drawing color at location (x,y) in viewpoint coordinates.
2661  */
2662 void draw_point(double x, double y) {
2663  // 4x4 point
2664  //glRectd(x - 2.0, y - 2.0, x + 2.0, y + 2.0);
2665  glBegin(GL_POINTS);
2666  glVertex2d(x, y);
2667  glEnd();
2668 }
2669 
2670 /*
2671  * draw_point
2672  * Draws a point in the current drawing color at location (x,y) in viewpoint coordinates.
2673  */
2674 void draw_point(const Point& pt) {
2675  // 4x4 point
2676  //glRectd(pt.x - 2.0, pt.y - 2.0, pt.x + 2.0, pt.y + 2.0);
2677  glBegin(GL_POINTS);
2678  glVertex2d(pt.x, pt.y);
2679  glEnd();
2680 }
2686 void set_point_size(int point_size) {
2687  glPointSize(static_cast<GLfloat>(point_size));
2688 }
2689 
2690 
2691 /*
2692  * draw_line
2693  * Draws a line from (x0,y0) to (x1,y1) in the current drawing color.
2694  */
2695 void draw_line(double x0, double y0, double x1, double y1) {
2696  glBegin(GL_LINES);
2697  glVertex2d(x0, y0);
2698  glVertex2d(x1, y1);
2699  glEnd();
2700 }
2701 
2702 void draw_dashed_line(double x0, double y0, double x1, double y1,
2703  int pattern) {
2704  glLineStipple(1, static_cast<GLushort>(pattern));
2705  glEnable(GL_LINE_STIPPLE);
2706  glBegin(GL_LINES);
2707  glVertex2d(x0, y0);
2708  glVertex2d(x1, y1);
2709  glEnd();
2710  glDisable(GL_LINE_STIPPLE);
2711 }
2712 
2713 /*
2714  * draw_rectangle
2715  * Draws a rectangle frame in the current drawing color at location (x,y) in viewpoint coordinates.
2716  */
2717 void draw_rectangle(double x, double y, double width, double height) {
2718  //glRectd(x, y, x + width, y + height);
2719  glBegin(GL_LINE_LOOP);
2720  glVertex2d(x, y);
2721  glVertex2d(x + width, y);
2722  glVertex2d(x + width, y + height);
2723  glVertex2d(x, y + height);
2724  //glVertex2d(x, y);
2725  glEnd();
2726 }
2727 
2728 /*
2729  * fill_rectangle
2730  * Draws a filled rectangle in the current drawing color at location (x,y) in viewpoint coordinates.
2731  */
2732 void fill_rectangle(double x, double y, double width, double height) {
2733  glBegin(GL_POLYGON);
2734  glVertex2d(x, y);
2735  glVertex2d(x + width, y);
2736  glVertex2d(x + width, y + height);
2737  glVertex2d(x, y + height);
2738  glEnd();
2739 }
2740 
2741 static const double DEG_TO_RAD = 3.1415926/180.0;
2742 
2743 void draw_circle(double x, double y, double radius) {
2744  const int NUM_SEGMENTS = 360;
2745  glBegin(GL_LINE_LOOP);
2746  for (int deg = 0; deg < NUM_SEGMENTS; deg++) {
2747  // Get the current angle
2748  //double theta = 2.0 * 3.1415926 * i/NUM_SEGMENTS;
2749  double theta = deg*DEG_TO_RAD;
2750  double edge_x = radius*cos(theta); // Calculate the x coordinate
2751  double edge_y = radius*sin(theta); // Calculate the y coordinate
2752 
2753  glVertex2d(x + edge_x, y + edge_y); // Output vertex
2754  }
2755  glEnd();
2756 }
2757 
2758 // Draw Filled Circle Adapted from code
2759 // on http://www.allegro.cc/forums/thread/588625
2760 void fill_circle(double x, double y, double radius) {
2761  const int NUM_SEGMENTS = 360;
2762  double y1 = y;
2763  double x1 = x;
2764  glBegin(GL_TRIANGLES);
2765  for(int deg = 0; deg <= NUM_SEGMENTS; deg++) {
2766  double angle = deg*DEG_TO_RAD;
2767  double x2 = x + radius*sin(angle);
2768  double y2 = y + radius*cos(angle);
2769  glVertex2d(x,y);
2770  glVertex2d(x1,y1);
2771  glVertex2d(x2,y2);
2772  y1 = y2;
2773  x1 = x2;
2774  }
2775  glEnd();
2776 }
2777 
2778 // Draws a polygon
2779 void draw_polygon(const std::vector<Point>& pts) {
2780  glBegin(GL_LINE_LOOP);
2781  for (auto& p : pts)
2782  glVertex2d(p.x, p.y);
2783  glEnd();
2784 }
2785 
2796 void draw_polygon(const Point *pts, int n) {
2797  glBegin(GL_LINE_LOOP);
2798  for (int i = 0; i < n; i++)
2799  glVertex2d(pts[i].x, pts[i].y);
2800  glEnd();
2801 
2802 }
2803 
2804 
2805 // Draw a filled polygon
2806 void fill_polygon(const std::vector<Point>& pts) {
2807  glBegin(GL_POLYGON);
2808  for (auto& p : pts)
2809  glVertex2d(p.x, p.y);
2810  glEnd();
2811 }
2812 
2823 void fill_polygon(const Point *pts, int n) {
2824  glBegin(GL_POLYGON);
2825  for (int i = 0; i < n; i++)
2826  glVertex2d(pts[i].x, pts[i].y);
2827  glEnd();
2828 }
2829 
2830 void draw_text(const std::string& text, double x, double y, int font_size) {
2831  void *font;
2832  switch (font_size) {
2833  case 12:
2834  font = GLUT_BITMAP_HELVETICA_12;
2835  break;
2836  case 18:
2837  font = GLUT_BITMAP_HELVETICA_18;
2838  break;
2839  case 915:
2840  font = GLUT_BITMAP_9_BY_15;
2841  break;
2842  case 813:
2843  font = GLUT_BITMAP_8_BY_13;
2844  break;
2845  default:
2846  font = GLUT_BITMAP_HELVETICA_10;
2847  }
2848  glRasterPos2d(x, y);
2849  const char *str = text.c_str();
2850  while (*str != '\0')
2851  glutBitmapCharacter(font, *str++);
2852 };
2853 
2854 
2868 void draw_text(const std::string& text, double x, double y, double scale) {
2869  glPushMatrix();
2870  glTranslated(x, y, 0);
2871  glScaled(scale, scale, scale);
2872  const char *str = text.c_str();
2873  while (*str != '\0')
2874  glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, *str++);
2875  glPopMatrix();
2876 
2877 };
2878 
2879 
2880 
2881 void draw_function(double (*f)(double),
2882  double begin_x, double end_x,
2883  double increment) {
2884  glBegin(GL_LINE_STRIP);
2885  for (double x = begin_x; x <= end_x; x += increment)
2886  glVertex2d(x, f(x));
2887  glEnd();
2888 }
2889 
2890 
2891 
2892 
2893 
2894 
2895 
2902  return glutGet(GLUT_SCREEN_WIDTH);
2903 }
2904 
2911  return glutGet(GLUT_SCREEN_HEIGHT);
2912 }
2913 
2923 template <typename T, typename... Args>
2924 inline void run(Args&&... args) {
2925  //std::make_shared<T>(args...)->run();
2926  T{args...}.run();
2927 }
2928 
2939 template <typename T, typename... Args>
2940 inline T *make_window(Args&&... args) {
2941  return new T(args...);
2942 }
2943 
2944 /****************************************
2945  * Utility functions
2946  ****************************************/
2947 
2948 
2949 // Creates a Stopwatch object
2950 // A newly minted object is not running and is in a "reset" state
2951 Stopwatch::Stopwatch(): start_time(0), end_time(0), running(false) {}
2952 
2953 // Starts the stopwatch. If there is no current
2954 // start time, the stopwatch has not been used or
2955 // has just been reset, so we record the current
2956 // system time to begin a new timing. If there is
2957 // a valid start time, we merely resume the current timing.
2958 // Puts the stopwatch object in the 'running' state.
2960  if (start_time == 0) // Need to start with a fresh timing?
2961  start_time = clock(); // If so, record start time
2962  running = true; // The clock is running
2963 }
2964 
2965 // Stops the stopwatch. Records the current
2966 // system time and puts the stopwatch object in
2967 // the 'not running' state.
2968 // If the stopwatch is already stopped, a diagnostic
2969 // message is issued, but the stored elapsed time is
2970 // unaffected.
2972  if (running) {
2973  end_time = clock();
2974  running = false;
2975  }
2976  else
2977  std::cout << "Stopwatch is not running\n";
2978 }
2979 
2980 // Reports the time elapsed between the
2981 // stopwatch's starting and stopping times.
2982 // If elapsed is called while the stopwatch
2983 // is running, the time elapsed since the start
2984 // time is reported,
2985 double Stopwatch::elapsed() const {
2986  if (running)
2987  return clock() - start_time;
2988  else
2989  return static_cast<double>(end_time - start_time)/CLOCKS_PER_SEC;
2990 }
2991 
2992 // Resets the stopwatch so a subsequent start begins recording
2993 // a new time. An attempt to reset a running stopwatch
2994 // produces an error message.
2996  if (!running)
2997  start_time = end_time = 0; // Reset times
2998  else
2999  std::cout << "Error: Cannot reset a stopwatch that is running\n";
3000 }
3001 
3002 // Pauses the program's execution for a period of
3003 // milliseconds.
3004 void pause(int msec) {
3005  if (msec > 0) {
3006  clock_t start_time = clock();
3007  while (clock() - start_time < msec)
3008  continue;
3009  }
3010 }
3011 
3012 
3013 
3014 /* Pseudorandom number routines */
3015 
3016 
3017 void set_random_seed(int seed) {
3018  if (seed < 0) {
3019  seed = seed; // Fix this
3020  }
3021  srand(static_cast<unsigned>(seed));
3022 }
3023 
3024 // Returns a pseudorandom number in the
3025 // range begin...end
3026 int random(int begin, int end) {
3027  int range = end - begin + 1;
3028  return rand() % range + begin;
3029 }
3030 
3039 int random(int n) {
3040  return rand() % n;
3041 }
3042 
3043 
3044 // Determines if |d1 - d2| < delta; in other words,
3045 // d1 and d2 are close enough to be considered "equal"
3046 bool equals(double d1, double d2, double delta) {
3047  return d1 == d2 || fabs(d1 - d2) < delta;
3048 }
3049 
3050 // Modern C++ provides standard functions for these:
3051 //static std::ostringstream internal_to_string_stream;
3052 //static std::string internal_to_string_buffer;
3053 //
3055 // * Converts an integer to a string so it can be displayed
3056 // * with draw_text.
3057 // * @param i the integer to convert
3058 // * @return the string representation of i
3059 // */
3060 //std::string to_string(int i) {
3061 // internal_to_string_stream.str("");
3062 // internal_to_string_stream << i;
3063 // internal_to_string_buffer = internal_to_string_stream.str();
3064 // return internal_to_string_buffer; // .c_str();
3065 //
3066 //}
3067 //
3069 // * Converts a double to a string so it can be displayed
3070 // * with draw_text.
3071 // * @param d the double to convert
3072 // * @return the string representation of d
3073 // */
3074 //std::string to_string(double d) {
3075 // internal_to_string_stream.str("");
3076 // internal_to_string_stream << d;
3077 // internal_to_string_buffer = internal_to_string_stream.str();
3078 // return internal_to_string_buffer; // .c_str();
3079 //}
3080 
3081 
3082 //-----------------------------------------------------------------------------------------
3083 // Procedural interface to the SGL
3084 
3085 // The default event handlers do nothing
3087 void procedural_default_mouse_pressed_function(double, double, MouseButton) {}
3088 void procedural_default_mouse_released_function(double, double, MouseButton) {}
3089 void procedural_default_mouse_moved_function(double, double) {}
3090 void procedural_default_mouse_dragged_function(double, double) {}
3091 void procedural_default_key_pressed_function(int, double, double) {}
3092 
3094 public:
3095  std::function<void()> paint_function;
3096  std::function<void(double, double, MouseButton)> mouse_pressed_function;
3097  std::function<void(double, double, MouseButton)> mouse_released_function;
3098  std::function<void(double, double)> mouse_moved_function;
3099  std::function<void(double, double)> mouse_dragged_function;
3100  std::function<void(int, double, double)> key_pressed_function;
3101 
3102  ProceduralWindow(const std::string& title, double x, double y, double width, double height) :
3103  ObjectWindow(title, x, y, width, height),
3104  mouse_pressed_function(procedural_default_mouse_pressed_function),
3105  mouse_released_function(procedural_default_mouse_released_function),
3106  mouse_moved_function(procedural_default_mouse_moved_function),
3107  mouse_dragged_function(procedural_default_mouse_dragged_function),
3108  key_pressed_function(procedural_default_key_pressed_function) {}
3109 
3110  void paint() override {
3111  paint_function();
3112  }
3113 
3114  void mouse_pressed(double x, double y, MouseButton b) override {
3115  mouse_pressed_function(x, y, b);
3116  }
3117 
3118  void mouse_released(double x, double y, MouseButton b) override {
3119  mouse_released_function(x, y, b);
3120  }
3121 
3122  void mouse_moved(double x, double y) override {
3123  mouse_moved_function(x, y);
3124  }
3125 
3126  void mouse_dragged(double x, double y) override {
3127  mouse_dragged_function(x, y);
3128  }
3129 
3130  void key_pressed(int k, double x, double y) override {
3131  key_pressed_function(k, x, y);
3132  }
3133 };
3134 
3135 
3136 // Global window used by the procedural code
3137 //static std::shared_ptr<ProceduralWindow> global_procedural_window;
3138 static ProceduralWindow *global_procedural_window;
3139 
3140 static void exit_error(const std::string& message) {
3141  std::cout << message << '\n';
3142  exit(1);
3143 }
3144 
3145 void create_window(const std::string& title, int x, int y, int width, int height) {
3146  if (global_procedural_window)
3147  exit_error("An application can create only one graphics window");
3148  //global_procedural_window = std::make_shared<ProceduralWindow>(title, x, y, width, height);
3149  global_procedural_window = make_window<ProceduralWindow>(title, x, y, width, height);
3150 }
3151 
3152 void run_window() {
3153  if (!global_procedural_window)
3154  exit_error("Cannot run_window: No graphics window exists (use create_window)");
3155  global_procedural_window->run();
3156 }
3157 
3159  if (!global_procedural_window)
3160  exit_error("Cannot update_window: No graphics window exists (use create_window)");
3161  global_procedural_window->repaint();
3162 }
3163 
3164 void set_paint_function(const std::function<void()>& f) {
3165  if (!global_procedural_window)
3166  exit_error("Cannot set_paint_function: No graphics window exists (use create_window)");
3167  global_procedural_window->paint_function = f;
3168 }
3169 
3170 void set_mouse_pressed_function(const std::function<void(double, double, MouseButton)>& f) {
3171  if (!global_procedural_window)
3172  exit_error("Cannot set_mouse_pressed_function: No graphics window exists (use create_window)");
3173  global_procedural_window->mouse_pressed_function = f;
3174 
3175 }
3176 
3177 void set_mouse_released_function(const std::function<void(double, double, MouseButton)>& f) {
3178  if (!global_procedural_window)
3179  exit_error("Cannot set_mouse_released_function: No graphics window exists (use create_window)");
3180  global_procedural_window->mouse_released_function = f;
3181 }
3182 
3183 void set_mouse_moved_function(const std::function<void(double, double)>& f) {
3184  if (!global_procedural_window)
3185  exit_error("Cannot set_mouse_moved_function: No graphics window exists (use create_window)");
3186  global_procedural_window->mouse_moved_function = f;
3187 }
3188 
3189 void set_mouse_dragged_function(const std::function<void(double, double)>& f) {
3190  if (!global_procedural_window)
3191  exit_error("Cannot set_mouse_dragged_function: No graphics window exists (use create_window)");
3192  global_procedural_window->mouse_dragged_function = f;
3193 }
3194 
3195 void set_key_pressed_function(const std::function<void(int, double, double)>& f) {
3196  if (!global_procedural_window)
3197  exit_error("Cannot set_key_pressed_function: No graphics window exists (use create_window)");
3198  global_procedural_window->key_pressed_function = f;
3199 }
3200 
3202  if (!global_procedural_window)
3203  exit_error("Cannot set_window_background: No graphics window exists (use create_window)");
3204  global_procedural_window->set_background_color(c);
3205 }
3206 
3207 void set_window_title(const std::string& str) {
3208  if (!global_procedural_window)
3209  exit_error("Cannot set_window_title: No graphics window exists (use create_window)");
3210  global_procedural_window->set_title(str);
3211 }
3212 
3213 
3214 
3215 } // End of namespace sgl
3216 
3217 #ifdef _MSC_VER
3218  #pragma warning(pop)
3219 #endif
3220 
3221 #endif
void remove(GraphicalObject *obj)
Definition: sgl.hpp:796
virtual void timer_expired()
Definition: sgl.hpp:681
CursorShape cursor
Definition: sgl.h:259
void mouse_dragged(double x, double y) override
Definition: sgl.hpp:768
void mouse_pressed(double x, double y, MouseButton b) override
Definition: sgl.hpp:3114
TimeDisplay(Color color, double x, double y, int height)
Definition: sgl.hpp:2144
virtual void clear()
Definition: sgl.hpp:531
KeyModifier
Definition: sgl.h:209
virtual int get_width() const
Definition: sgl.hpp:573
void draw_dashed_line(double x0, double y0, double x1, double y1, int pattern=0x00FF)
Definition: sgl.hpp:2702
SevenSegmentDigit seconds_ones
Definition: sgl.h:1950
void mouse_released(double x, double y, MouseButton button) override
Definition: sgl.hpp:742
virtual void start_timer(int msec)
Definition: sgl.hpp:676
virtual double get_min_y() const
Definition: sgl.hpp:590
void set_random_seed(int seed=-1)
Definition: sgl.hpp:3017
~OGLWindow()
Definition: sgl.hpp:1217
void prepaint() override
Definition: sgl.hpp:724
virtual void set_visible(bool visible)
Definition: sgl.hpp:438
int get_value() const
Definition: sgl.hpp:1665
int get_value() const
Definition: sgl.hpp:1968
void postpaint() override
Definition: sgl.hpp:1229
virtual void mouse_dragged(double x, double y)
Definition: sgl.hpp:2435
void move_to(double x, double y)
Definition: sgl.hpp:1703
void set_mouse_dragged_function(const std::function< void(double, double)> &f)
Definition: sgl.hpp:3189
void initialize(const std::string &title, int left, int top, int width, int height, double min_x, double max_x, double min_y, double max_y)
Definition: sgl.hpp:311
MouseButton
Definition: sgl.h:134
bool visible
Definition: sgl.h:1961
void draw_line(double x0, double y0, double x1, double y1)
Definition: sgl.hpp:2695
double min_x
Definition: sgl.h:525
void mouse_pressed(double x, double y, MouseButton button) override
Definition: sgl.hpp:734
void reset()
Definition: sgl.hpp:2995
void set_leading_zeros(bool flag)
Definition: sgl.hpp:2077
virtual CursorShape get_cursor()
Definition: sgl.hpp:461
void set_value(int value)
Definition: sgl.hpp:1738
virtual int get_x() const
Definition: sgl.hpp:563
Color color
Definition: sgl.h:1536
DoubleDigit(Color color, double x, double y, double height)
Definition: sgl.hpp:1800
virtual void draw_axes(double x_inc, double y_inc) const
Definition: sgl.hpp:500
virtual int get_y() const
Definition: sgl.hpp:568
virtual void move_to(double left, double bottom)
Definition: sgl.hpp:2441
SevenSegmentDigit minutes_ones
Definition: sgl.h:1944
ObjectWindow()
Definition: sgl.hpp:715
void paint() const
Definition: sgl.hpp:1091
void mouse_dragged(double x, double y) override
Definition: sgl.hpp:1882
virtual double get_height() const
Definition: sgl.hpp:2387
void key_pressed(int k, double x, double y) override
Definition: sgl.hpp:775
void resize(double inc)
Definition: sgl.hpp:2018
Definition: sgl.h:975
double left
Definition: sgl.h:243
Definition: sgl.h:75
virtual double get_width() const
Definition: sgl.hpp:2383
bool visible
Definition: sgl.h:1834
void mouse_dragged(double x, double y) override
Definition: sgl.hpp:1786
void increment()
Definition: sgl.hpp:2000
std::string version()
Definition: sgl.hpp:200
bool leading_zeros
Definition: sgl.h:1830
void paint() const override
Definition: sgl.hpp:1725
virtual void execute_handler(int n)
Definition: sgl.hpp:2555
double max_x
Definition: sgl.h:529
void fill_circle(double x, double y, double radius)
Definition: sgl.hpp:2760
void set_window_background(const Color &c)
Definition: sgl.hpp:3201
Stopwatch()
Definition: sgl.hpp:2951
DisplayDigit(Color color, double x, double y, double height)
Definition: sgl.hpp:1719
int get_value() const
Definition: sgl.hpp:1835
~ObjectWindow()
Definition: sgl.hpp:718
void draw_rectangle(double x, double y, double width, double height)
Definition: sgl.hpp:2717
int get_value() const
Definition: sgl.hpp:2219
Window()
Definition: sgl.hpp:399
clock_t start_time
Definition: sgl.h:2431
CompositeObject()
Definition: sgl.hpp:1112
void set_value(int sec)
Definition: sgl.hpp:2192
virtual void mouse_released(double x, double y, MouseButton button)
Definition: sgl.hpp:621
virtual CursorShape set_cursor(CursorShape cursor)
Definition: sgl.hpp:2528
void move_to(double x, double y) override
Definition: sgl.hpp:2296
SevenSegmentDigit ones
Definition: sgl.h:1729
virtual Window * get_window() const
Definition: sgl.hpp:2519
virtual void mouse_moved(double x, double y)
Definition: sgl.hpp:2491
virtual ~PopupMenu()
Definition: sgl.hpp:2569
virtual void set_mouse_over(bool flag)
Definition: sgl.hpp:2446
void internal_add(GraphicalObject *obj)
Definition: sgl.hpp:785
virtual void repaint()
Definition: sgl.hpp:539
virtual void set_size(int width, int height)
Definition: sgl.hpp:427
double x
Definition: sgl.h:1539
void mouse_released(double x, double y, MouseButton b) override
Definition: sgl.hpp:3118
virtual void postpaint()
Definition: sgl.hpp:555
SevenSegmentDigit tens
Definition: sgl.h:1726
virtual double get_max_x() const
Definition: sgl.hpp:586
void set_paint_function(const std::function< void()> &f)
Definition: sgl.hpp:3164
void set_value(int value)
Definition: sgl.hpp:1955
SevenSegmentDigit minutes_tens
Definition: sgl.h:1941
void remove_all()
Definition: sgl.hpp:807
Definition: sgl.h:68
void set_window_title(const std::string &str)
Definition: sgl.hpp:3207
void update_window()
Definition: sgl.hpp:3158
void resize(double inc)
Definition: sgl.hpp:1865
std::vector< GraphicalObject * > objects
Definition: sgl.h:1309
void set_visible(bool flag)
Definition: sgl.hpp:2087
double y_hit_offset
Definition: sgl.h:239
GraphicalObject * hit(double x, double y) const
Definition: sgl.hpp:818
void move_to(double x, double y) override
Definition: sgl.hpp:1144
std::function< void()> MenuItemFunction
Definition: sgl.h:968
Definition: sgl.h:224
Definition: sgl.h:98
void draw_separator(const SevenSegmentDigit &left_ones, const SevenSegmentDigit &right_tens) const
Definition: sgl.hpp:2099
virtual double get_left() const
Definition: sgl.hpp:2375
virtual ~GraphicalObject()
Definition: sgl.hpp:2369
virtual void mouse_entered()
Definition: sgl.hpp:628
void update_segment_locations()
Definition: sgl.hpp:1475
bool leading_zero
Definition: sgl.h:1733
virtual int get_height() const
Definition: sgl.hpp:578
BitmapObject(const char *filename, double x, double y, double width, double height)
Definition: sgl.hpp:1081
void draw_function(double(*f)(double), double begin_x, double end_x, double delta)
Definition: sgl.hpp:2881
double width
Definition: sgl.h:251
void set_leading_units(bool flag)
Definition: sgl.hpp:2315
void set_line_width(double width)
Definition: sgl.hpp:2627
virtual void prepaint()
Definition: sgl.hpp:549
virtual void paint_all()
Definition: sgl.hpp:543
static void process_menu_events(int option)
Definition: sgl.hpp:2559
int random(int begin, int end)
Definition: sgl.hpp:3026
void set_visible(bool flag)
Definition: sgl.hpp:2325
void decrement()
Definition: sgl.hpp:1681
double x_hit_offset
Definition: sgl.h:235
const Color BLACK
virtual void mouse_released(double x, double y, MouseButton button)
Definition: sgl.hpp:2478
void increment()
Definition: sgl.hpp:1673
void resize(double inc)
Definition: sgl.hpp:1773
double get_x() const
Definition: sgl.hpp:1552
clock_t end_time
Definition: sgl.h:2434
void postpaint() override
Definition: sgl.hpp:728
ObjectWindow * window
Definition: sgl.h:231
void resize(double inc)
Definition: sgl.hpp:1691
virtual void set_position(int x, int y)
Definition: sgl.hpp:416
virtual void mouse_pressed(double x, double y, MouseButton button)
Definition: sgl.hpp:619
double get_height() const
Definition: sgl.hpp:1568
void set_mouse_moved_function(const std::function< void(double, double)> &f)
Definition: sgl.hpp:3183
T * make_window(Args &&... args)
Definition: sgl.hpp:2940
void stop()
Definition: sgl.hpp:2971
KeyModifier key_mods
Definition: sgl.h:545
void fill_rectangle(double x, double y, double width, double height)
Definition: sgl.hpp:2732
double height
Definition: sgl.h:1542
Definition: sgl.h:981
void paint() const override
Definition: sgl.hpp:1932
virtual void set_background_color(const Color &color)
Definition: sgl.hpp:473
std::vector< GraphicalObject * >::iterator begin()
Definition: sgl.hpp:831
void prepaint() override
Definition: sgl.hpp:1223
void procedural_default_paint_function()
Definition: sgl.hpp:3086
void set_mouse_released_function(const std::function< void(double, double, MouseButton)> &f)
Definition: sgl.hpp:3177
virtual void key_pressed(int k, double x, double y)
Definition: sgl.hpp:641
void increment()
Definition: sgl.hpp:2227
OGLWindow(const std::string &title, int left, int top, int width, int height)
Definition: sgl.hpp:1204
void mouse_moved(double x, double y) override
Definition: sgl.hpp:3122
void increment()
Definition: sgl.hpp:1755
virtual double get_bottom() const
Definition: sgl.hpp:2379
Definition: sgl.hpp:3093
SevenSegmentDigit led
Definition: sgl.h:1656
SevenSegmentDigit hours_ones
Definition: sgl.h:1938
void paint_without_leading_units() const
Definition: sgl.hpp:2114
void create_window(const std::string &title, int x, int y, int width, int height)
Definition: sgl.hpp:3145
void internal_add(GraphicalObject *obj)
Definition: sgl.hpp:1161
virtual CursorShape set_cursor(CursorShape cursor)
Definition: sgl.hpp:450
void draw_circle(double x, double y, double radius)
Definition: sgl.hpp:2743
SevenSegmentDigit(Color color, double x, double y, double height)
Definition: sgl.hpp:1543
void increment()
Definition: sgl.hpp:1843
void set_color(const Color &color)
Definition: sgl.hpp:2619
void start()
Definition: sgl.hpp:2959
void paint() const
Definition: sgl.hpp:1575
int get_value() const
Definition: sgl.hpp:1746
virtual CursorShape get_cursor()
Definition: sgl.hpp:2540
const unsigned id
Definition: sgl.h:268
double x
Definition: sgl.h:77
void paint() const override
Definition: sgl.hpp:1809
void set_key_pressed_function(const std::function< void(int, double, double)> &f)
Definition: sgl.hpp:3195
bool make_checkerboard()
Definition: sgl.hpp:1030
bool equals(double d1, double d2, double delta)
Definition: sgl.hpp:3046
void set_mouse_pressed_function(const std::function< void(double, double, MouseButton)> &f)
Definition: sgl.hpp:3170
double elapsed() const
Definition: sgl.hpp:2985
virtual void set_title(const std::string &str)
Definition: sgl.hpp:535
bool visible
Definition: sgl.h:1737
virtual void mouse_exited()
Definition: sgl.hpp:635
void set_visible(bool flag)
Definition: sgl.hpp:1904
int seconds
Definition: sgl.h:1953
virtual void set_viewport(double left, double right, double bottom, double top)
Definition: sgl.hpp:466
void decrement()
Definition: sgl.hpp:2008
void paint() override
Definition: sgl.hpp:3110
double bottom
Definition: sgl.h:247
Definition: sgl.h:520
double y
Definition: sgl.h:80
PopupMenu()
Definition: sgl.hpp:2563
void pause(int msec)
Definition: sgl.hpp:3004
void set_leading_zero(bool flag)
Definition: sgl.hpp:1894
void mouse_dragged(double x, double y) override
Definition: sgl.hpp:2275
virtual void set_window_size(int w, int h)
Definition: sgl.hpp:598
double get_y() const
Definition: sgl.hpp:1560
Definition: sgl.h:1070
void set_value(int value)
Definition: sgl.hpp:1826
virtual void mouse_pressed(double x, double y, MouseButton button)
Definition: sgl.hpp:2463
void decrement()
Definition: sgl.hpp:1853
double height
Definition: sgl.h:255
SevenSegmentDigit seconds_tens
Definition: sgl.h:1947
std::vector< GraphicalObject * > object_list
Definition: sgl.h:1073
void mouse_moved(double x, double y) override
Definition: sgl.hpp:751
virtual Window * set_window(ObjectWindow *win)
Definition: sgl.hpp:2513
Definition: sgl.h:1530
void mouse_dragged(double x, double y) override
Definition: sgl.hpp:2039
void resize(double inc)
Definition: sgl.hpp:2245
virtual bool hit(double x, double y)
Definition: sgl.hpp:2414
int get_screen_width()
Definition: sgl.hpp:2901
virtual void mouse_moved(double x, double y)
Definition: sgl.hpp:615
CursorShape
Definition: sgl.h:171
bool running
Definition: sgl.h:2437
virtual void remove_menu_item(const std::string &item)
Definition: sgl.hpp:2592
double max_y
Definition: sgl.h:537
void draw_polygon(const std::vector< Point > &pts)
Definition: sgl.hpp:2779
virtual double get_max_y() const
Definition: sgl.hpp:594
int current_value
Definition: sgl.h:1533
virtual void set(double x, double y, double width, double height)
Definition: sgl.hpp:2402
double red
Definition: sgl.h:101
virtual void add_menu_item(const std::string &item, MenuItemFunction func)
Definition: sgl.hpp:2571
void fill_polygon(const std::vector< Point > &pts)
Definition: sgl.hpp:2806
bool intersect(const GraphicalObject &obj1, const GraphicalObject &obj2)
Definition: sgl.hpp:2639
void run(Args &&... args)
Definition: sgl.hpp:2924
void decrement()
Definition: sgl.hpp:1763
void initialize_graphics(unsigned int mode)
Definition: sgl.hpp:148
void paint() const override
Definition: sgl.hpp:2159
double green
Definition: sgl.h:103
virtual void paint()=0
CursorShape normal_cursor
Definition: sgl.h:540
Multidigit(int n, Color color, double x, double y, double height)
Definition: sgl.hpp:1920
virtual double get_min_x() const
Definition: sgl.hpp:582
GraphicalObject(double left, double bottom, double width, double height)
Definition: sgl.hpp:2338
bool mouse_over
Definition: sgl.h:263
void draw_text(const std::string &text, double x, double y, int font_size)
Definition: sgl.hpp:2830
virtual void replace_menu_item(const std::string &old_name, const std::string &new_name, MenuItemFunction func)
Definition: sgl.hpp:2576
void key_pressed(int k, double x, double y) override
Definition: sgl.hpp:3130
virtual ~Window()
Definition: sgl.hpp:403
KeyModifier get_key_modifiers() const
Definition: sgl.hpp:668
int get_screen_height()
Definition: sgl.hpp:2910
void run_window()
Definition: sgl.hpp:3152
void mouse_dragged(double x, double y) override
Definition: sgl.hpp:3126
double blue
Definition: sgl.h:105
virtual void move_to(double left, double bottom) override
Definition: sgl.hpp:2059
double min_y
Definition: sgl.h:533
bool leading_units
Definition: sgl.h:1957
std::vector< GraphicalObject * >::iterator end()
Definition: sgl.hpp:841
void draw_point(double x, double y)
Definition: sgl.hpp:2662
virtual void mouse_dragged(double x, double y)
Definition: sgl.hpp:617
void set_key_modifiers(KeyModifier mod)
Definition: sgl.hpp:672
virtual void resized(int w, int h)
Definition: sgl.hpp:602
virtual void key_pressed(int k, double x, double y)
Definition: sgl.hpp:2508
void decrement()
Definition: sgl.hpp:2235
SevenSegmentDigit hours_tens
Definition: sgl.h:1935
void paint() const override
Definition: sgl.hpp:1130
bool read_BMP_file(const char *fname)
Definition: sgl.hpp:942
std::vector< SevenSegmentDigit > digits
Definition: sgl.h:1823
void set_point_size(int point_size)
Definition: sgl.hpp:2686
virtual void activate()
Definition: sgl.hpp:2601
void set_value(int value)
Definition: sgl.hpp:1657