20 #include <GL/freeglut.h>
22 # include <sys/time.h>
26 #include "view_support.h"
29 #include "view_data.cpp"
37 #define HERMES_WAIT_CLOSE_MSG "close all views to continue"
38 #define HERMES_WAIT_KEYPRESS_MSG "press spacebar to continue"
40 int View::screenshot_no = 1;
44 jitter_x = jitter_y = 0.0;
45 dragging = scaling =
false;
53 pal_filter = GL_NEAREST;
57 scale_focused = scale_dragging =
false;
58 pos_horz = pos_vert = 0;
59 scale_x = scale_y = labels_width = 0;
63 strcpy(scale_fmt,
"%.3g");
64 scale_fixed_width = -1;
65 want_screenshot =
false;
71 View::View(
const char* title, WinGeom* wg) :
83 output_x = H2D_DEFAULT_X_POS;
84 output_y = H2D_DEFAULT_Y_POS;
85 output_width = H2D_DEFAULT_WIDTH;
86 output_height = H2D_DEFAULT_HEIGHT;
92 output_width = wg->width;
93 output_height = wg->height;
99 View::View(
char* title, WinGeom* wg) :
100 view_not_reset(true),
111 output_x = H2D_DEFAULT_X_POS;
112 output_y = H2D_DEFAULT_Y_POS;
113 output_width = H2D_DEFAULT_WIDTH;
114 output_height = H2D_DEFAULT_HEIGHT;
120 output_width = wg->width;
121 output_height = wg->height;
136 return add_view(
this, output_x, output_y, output_width, output_height, title.c_str());
155 std::stringstream str;
165 default:
throw Hermes::Exceptions::Exception(
"Unknown wait event");
break;
168 str <<
" >>" << std::endl;
175 default:
throw Hermes::Exceptions::Exception(
"Unknown wait event");
break;
181 bool do_refresh =
true;
194 double mesh_width = vertices_max_x - vertices_min_x;
197 double usable_width = output_width - 2*margin - lspace - rspace;
198 double usable_height = output_height - 2*margin;
201 if(usable_width / usable_height < mesh_width / mesh_height)
202 scale = usable_width / mesh_width;
204 scale = usable_height / mesh_height;
205 log_scale = log(scale) / log(H2DV_SCALE_LOG_BASE);
208 trans_x = -scale * (vertices_min_x + vertices_max_x) / 2;
215 void View::on_create(
int output_id)
217 this->output_id = output_id;
219 set_palette_filter(pal_filter == GL_LINEAR);
222 void View::on_close()
231 glClearColor(1.0, 1.0, 1.0, 0.0);
232 glClear(GL_COLOR_BUFFER_BIT);
235 void View::pre_display()
251 display_antialiased();
255 if(b_help) draw_help();
256 else if(b_scale) scale_dispatch();
267 glReadBuffer(GL_BACK_LEFT);
268 save_screenshot_internal(screenshot_filename.c_str());
269 want_screenshot =
false;
280 static float jitter16[16][2] =
282 { 0.4375, 0.4375 }, { 0.1875, 0.5625 },
283 { 0.9375, 1.1875 }, { 0.4375, 0.9375-1 },
284 { 0.6875, 0.5625 }, { 0.1875, 0.0625 },
285 { 0.6875, 0.3125 }, { 0.1875, 0.3125 },
286 { 0.4375, 0.1875 }, { 0.9375-1, 0.4375 },
287 { 0.6875, 0.8125 }, { 0.4375, 0.6875 },
288 { 0.6875, 0.0625 }, { 0.9375, 0.9375 },
289 { 1.1875, 0.8125 }, { 0.9375, 0.6875 }
292 void View::display_antialiased()
294 glClear(GL_ACCUM_BUFFER_BIT);
295 for (
int i = 0; i < 16; i++)
297 jitter_x = jitter16[i][0];
298 jitter_y = jitter16[i][1];
299 set_ortho_projection();
302 glAccum(GL_ACCUM, 1.0 / 16);
304 glAccum(GL_RETURN, 1.0);
305 jitter_x = jitter_y = 0.0;
308 void View::set_ortho_projection(
bool no_jitter)
310 double jx = no_jitter ? 0.0 : jitter_x;
311 double jy = no_jitter ? 0.0 : jitter_y;
313 glMatrixMode(GL_PROJECTION);
315 glOrtho(jx, output_width + jx, output_height-1 + jy, -1 + jy, -10, 10);
317 glMatrixMode(GL_MODELVIEW);
321 void View::set_3d_projection(
int fov,
double znear,
double zfar)
323 double top = znear * tan((
double) fov / 2.0 / 180.0 * M_PI);
324 double right = (double) output_width / output_height * top;
325 double left = -right;
326 double bottom = -top;
327 double offsx = (right - left) / output_width * jitter_x;
328 double offsy = (top - bottom) / output_height * jitter_y;
330 glMatrixMode(GL_PROJECTION);
332 glFrustum(left - offsx, right - offsx, bottom - offsy, top - offsy, znear, zfar);
338 double frame_time_sum = 0;
339 for(
int i = 0; i < FPS_FRAME_SIZE; i++)
343 unsigned char buffer[128];
344 sprintf((
char*)buffer,
"avg. frame: %.1f ms", (
float)(frame_time_sum / FPS_FRAME_SIZE));
347 void* font = GLUT_BITMAP_HELVETICA_10;
348 int width_px = glutBitmapLength(font, buffer);
349 int height_px = glutBitmapHeight(font);
350 int edge_thickness = 2;
351 set_ortho_projection(
false);
355 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
357 glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
358 glVertex2i(output_width - (width_px + 2*edge_thickness), 0);
359 glVertex2i(output_width, 0);
360 glVertex2i(output_width, height_px + 2*edge_thickness);
361 glVertex2i(output_width - (width_px + 2*edge_thickness), height_px + 2*edge_thickness);
366 glColor3f(1.0f, 0.0f, 0.0f);
367 glRasterPos2i(output_width - (width_px + edge_thickness), edge_thickness + height_px);
369 glutBitmapString(font, buffer);
372 void View::on_reshape(
int width,
int height)
374 glViewport(0, 0, width, height);
376 output_width = width;
377 output_height = height;
381 void View::on_mouse_move(
int x,
int y)
385 trans_x += (x - mouse_x);
386 trans_y += (mouse_y - y);
391 log_scale += (mouse_y - y);
392 scale = pow(H2DV_SCALE_LOG_BASE, log_scale);
393 trans_x = scx - objx * scale - center_x;
394 trans_y = center_y - objy * scale - scy;
397 else if(scale_dragging)
399 int oldv = pos_vert, oldh = pos_horz;
400 pos_horz = (x > output_width/2);
401 pos_vert = (y < output_height/2);
402 if(pos_horz != oldh || pos_vert != oldv)
410 bool oldf = scale_focused;
411 scale_focused = (x >= scale_x && x <= scale_x + scale_width &&
412 y >= scale_y && y <= scale_y + scale_height);
413 if(oldf != scale_focused)
420 void View::on_left_mouse_down(
int x,
int y)
423 scale_dragging =
true;
431 void View::on_left_mouse_up(
int x,
int y)
433 scaling = dragging = scale_dragging =
false;
437 void View::on_right_mouse_down(
int x,
int y)
443 objx = (x - center_x - trans_x) / scale;
444 objy = (center_y - y - trans_y) / scale;
449 void View::on_right_mouse_up(
int x,
int y)
451 scaling = dragging =
false;
454 void View::on_key_down(
unsigned char key,
int x,
int y)
456 const char *file_name = NULL;
476 const char *file_name = get_screenshot_file_name();
477 glReadBuffer(GL_FRONT_LEFT);
478 save_screenshot_internal(file_name);
500 default:
throw Hermes::Exceptions::Exception(
"Invalid palette type");
515 void View::on_special_key(
int key,
int x,
int y)
528 this->warn(
"Function View::wait_for_keypress deprecated: use View::wait instead");
532 void View::wait_for_close()
540 void View::wait_for_draw()
550 if(output_id >= 0 && !frame_ready)
563 LARGE_INTEGER freq, ticks;
564 QueryPerformanceFrequency(&freq);
565 QueryPerformanceCounter(&ticks);
566 return (1000.0 * (
double)ticks.QuadPart) / (double)freq.QuadPart;
569 gettimeofday(&tv, NULL);
570 return (
double) tv.tv_sec * 1000 + (double) tv.tv_usec / 1000;
576 bool do_set_title =
true;
584 do_set_title =
false;
597 else if(x > 1.0) x = 1.0;
598 x *= num_pal_entries;
600 gl_color[0] = palette_data[n][0];
601 gl_color[1] = palette_data[n][1];
602 gl_color[2] = palette_data[n][2];
605 gl_color[0] = gl_color[1] = gl_color[2] = (float)x;
607 gl_color[0] = gl_color[1] = gl_color[2] = (float)(1.0 - x);
609 gl_color[0] = gl_color[1] = gl_color[2] = 1.0f;
612 void View::set_num_palette_steps(
int num)
615 if(num > 256) num = 256;
630 unsigned char palette[256][3];
631 for (i = 0; i < pal_steps; i++)
635 palette[i][0] = (
unsigned char) (gl_color[0] * 255);
636 palette[i][1] = (
unsigned char) (gl_color[1] * 255);
637 palette[i][2] = (
unsigned char) (gl_color[2] * 255);
639 for (i = pal_steps; i < 256; i++)
640 memcpy(palette[i], palette[pal_steps-1], 3);
645 glTexImage1D(GL_TEXTURE_1D, 0, 3, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, palette);
646 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
647 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
650 void View::set_palette_filter(
bool linear)
654 pal_filter = linear ? GL_LINEAR : GL_NEAREST;
659 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, pal_filter);
660 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, pal_filter);
680 void View::update_tex_adjust()
682 if(pal_filter == GL_LINEAR)
684 tex_scale = (double) (pal_steps-1) / 256.0;
685 tex_shift = 0.5 / 256.0;
689 tex_scale = (double) pal_steps / 256.0;
694 void View::set_min_max_range(
double min,
double max)
699 this->warn(
"Upper bound set below the lower bound: reversing to (%f, %f).", min, max);
711 void View::auto_min_max_range()
722 void View::get_min_max_range(
double& min,
double& max)
730 void View::draw_text(
double x,
double y,
const char* text,
int align)
732 void* font = GLUT_BITMAP_9_BY_15;
735 int width = glutBitmapLength(font, (
const unsigned char*) text);
736 if(align == 1) x -= width;
737 else x -= (double) width / 2;
741 glDisable(GL_TEXTURE_1D);
742 glDisable(GL_LIGHTING);
744 glRasterPos2d((
int) (x + 0.5), (
int) (y + 0.5));
745 glutBitmapString(font, (
const unsigned char*) text);
748 int View::get_text_width(
const char* text)
750 void* font = GLUT_BITMAP_9_BY_15;
751 return glutBitmapLength(font, (
const unsigned char*) text);
754 void View::draw_help()
757 set_ortho_projection(
true);
758 glDisable(GL_DEPTH_TEST);
759 glDisable(GL_LIGHTING);
760 glDisable(GL_TEXTURE_1D);
761 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
763 const char* text = get_help_text();
766 for (
const char* p = text; *p; p++)
769 int width = get_text_width(text);
770 int height = n * glutBitmapHeight(GLUT_BITMAP_9_BY_15);
771 int x = 10, y = 10, b = 6;
774 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
775 glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
777 glVertex2d(x, y + height + 2*b);
778 glVertex2d(x + width + 2*b, y + height + 2*b);
779 glVertex2d(x + width + 2*b, y);
785 draw_text(x + b, y + b+7, text);
790 char* View::get_screenshot_file_name()
792 static char file_name[1024] = { 0 };
793 bool got_file_name =
false;
796 sprintf(file_name,
"screen%03d.bmp", screenshot_no);
797 FILE *f = fopen(file_name,
"r");
799 got_file_name =
true;
804 while (!got_file_name);
808 typedef unsigned int dword;
809 typedef unsigned short word;
811 const word BITMAP_ID = 0x4D42;
839 void View::save_screenshot_internal(
const char *file_name)
846 if((pixels = (
char*) malloc(4 * output_width * output_height)) == NULL)
847 throw Hermes::Exceptions::Exception(
"Could not allocate memory for pixel data");
851 glReadPixels(0, 0, output_width, output_height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
853 glReadPixels(0, 0, output_width, output_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
854 this->warn(
"BGRA format not supported. Saved image will have inverted colors");
857 FILE* file = fopen(file_name,
"wb");
859 throw Hermes::Exceptions::Exception(
"Could not open '%s' for writing", file_name);
862 file_header.type = BITMAP_ID;
864 4 * output_width * output_height;
865 file_header.reserved1 = file_header.reserved2 = 0;
866 file_header.off_bits = 14 + 40;
868 if(fwrite(&file_header,
sizeof(file_header), 1, file) != 1)
871 throw Hermes::Exceptions::Exception(
"Error writing bitmap header");
875 info_header.size =
sizeof(BitmapInfoHeader);
876 info_header.width = output_width;
877 info_header.height = output_height;
878 info_header.planes = 1;
879 info_header.bit_count = 32;
880 info_header.compression = 0;
881 info_header.size_image = output_width * output_height * 4;
882 info_header.xdpi = 2835;
883 info_header.ydpi = 2835;
884 info_header.clr_used = 0;
885 info_header.clr_important = 0;
887 if(fwrite(&info_header,
sizeof(info_header), 1, file) != 1)
890 throw Hermes::Exceptions::Exception(
"Error writing bitmap header");
894 if(fwrite((GLubyte*) pixels, 1, info_header.size_image, file) != info_header.size_image)
897 throw Hermes::Exceptions::Exception(
"Error writing pixel data");
901 free((
void*) pixels);
902 printf(
"Image \"%s\" saved.\n", file_name);
909 hq_frame = high_quality;
910 want_screenshot =
true;
911 screenshot_filename = bmpname;
922 sprintf(buffer, format, number);
926 int View::measure_scale_labels()
929 for (
int i = 0; i <= scale_numticks + 1; i++)
931 double value = range_min + (double) i * (range_max - range_min) / (scale_numticks + 1);
932 if(fabs(value) < 1e-8) value = 0.0;
934 sprintf(text, scale_fmt, value);
935 int w = get_text_width(text);
936 if(w > result) result = w;
941 void View::draw_continuous_scale(
char* title,
bool righttext)
944 double y0 = scale_y + scale_height;
946 set_ortho_projection(
true);
947 glDisable(GL_DEPTH_TEST);
948 glDisable(GL_LIGHTING);
949 glDisable(GL_TEXTURE_1D);
950 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
955 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
956 glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
957 int rt = righttext ? 0 : labels_width + 8;
959 glVertex2d(scale_x - b - rt, y0 + 5 + b);
960 glVertex2d(scale_x + scale_width + 8 + labels_width + b - rt, y0 + 5 + b);
961 glVertex2d(scale_x + scale_width + 8 + labels_width + b - rt, scale_y - 5 - b);
962 glVertex2d(scale_x - b - rt, scale_y - 5 - b);
967 glColor3f(0.0f, 0.0f, 0.0f);
969 glVertex2d(scale_x, scale_y);
970 glVertex2d(scale_x, scale_y + scale_height + 1);
971 glVertex2d(scale_x + scale_width + 1, scale_y + scale_height + 1);
972 glVertex2d(scale_x + scale_width + 1, scale_y);
975 glEnable(GL_TEXTURE_1D);
977 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
979 glTexCoord1d(tex_scale + tex_shift);
980 glVertex2d(scale_x + 1, scale_y + 1);
981 glVertex2d(scale_x + scale_width, scale_y + 1);
982 glTexCoord1d(tex_shift);
983 glVertex2d(scale_x + scale_width, scale_y + scale_height);
984 glVertex2d(scale_x + 1, scale_y + scale_height);
988 glDisable(GL_TEXTURE_1D);
992 glColor4f(1.0f, 1.0f, 1.0f, 0.3f);
994 glVertex2d(scale_x + 1, scale_y + 1);
995 glVertex2d(scale_x + scale_width, scale_y + 1);
996 glVertex2d(scale_x + scale_width, scale_y + scale_height);
997 glVertex2d(scale_x + 1, scale_y + scale_height);
1003 glDisable(GL_BLEND);
1004 glDisable(GL_LINE_STIPPLE);
1007 for (i = 0; i < scale_numticks; i++)
1009 y0 = scale_y + scale_height - (double) (i + 1) * scale_height / (scale_numticks + 1);
1010 glVertex2d(scale_x, y0);
1011 glVertex2d(scale_x + 0.2 * scale_width + 1, y0);
1012 glVertex2d(scale_x + 0.8 * scale_width, y0);
1013 glVertex2d(scale_x + scale_width, y0);
1018 for (i = 0; i <= scale_numticks + 1; i++)
1020 double value = range_min + (double) i * (range_max - range_min) / (scale_numticks + 1);
1021 if(fabs(value) < 1e-8) value = 0.0;
1023 sprintf(text, scale_fmt, value);
1024 y0 = scale_y + scale_height - (double) i * scale_height / (scale_numticks + 1);
1026 draw_text(scale_x + scale_width + 8, y0, text);
1028 draw_text(scale_x - 8, y0, text, 1);
1032 void View::draw_discrete_scale(
int numboxes,
const char* boxnames[],
const float boxcolors[][3])
1034 set_ortho_projection(
true);
1035 glDisable(GL_DEPTH_TEST);
1036 glDisable(GL_LIGHTING);
1037 glDisable(GL_TEXTURE_1D);
1038 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1043 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1044 glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
1046 glVertex2d(scale_x - b, scale_y - b);
1047 glVertex2d(scale_x - b, scale_y + scale_height + b + 1);
1048 glVertex2d(scale_x + scale_width + b + 1, scale_y + scale_height + b + 1);
1049 glVertex2d(scale_x + scale_width + b + 1, scale_y - b);
1053 glDisable(GL_BLEND);
1055 for (
int i = 0; i < numboxes; i++)
1057 glColor3f(0.0, 0.0, 0.0);
1059 glVertex2d(scale_x, y);
1060 glVertex2d(scale_x, y + scale_box_height + 1);
1061 glVertex2d(scale_x + scale_width + 1, y + scale_box_height + 1);
1062 glVertex2d(scale_x + scale_width + 1, y);
1065 const float* color = boxcolors[numboxes-1-i];
1066 float bcolor[3] = { color[0], color[1], color[2] };
1069 bcolor[0] = color[0]*0.7f + 1.0f*0.3f;
1070 bcolor[1] = color[1]*0.7f + 1.0f*0.3f;
1071 bcolor[2] = color[2]*0.7f + 1.0f*0.3f;
1074 glColor3f(bcolor[0], bcolor[1], bcolor[2]);
1076 glVertex2d(scale_x + 1, y + 1);
1077 glVertex2d(scale_x + 1, y + scale_box_height);
1078 glVertex2d(scale_x + scale_width, y + scale_box_height);
1079 glVertex2d(scale_x + scale_width, y + 1);
1082 if((color[0] + color[1] + color[2]) / 3 > 0.5)
1087 int a = scale_x + scale_width/2;
1088 int b = y + scale_box_height/2;
1089 draw_text(a, b, boxnames[numboxes-1-i], 0);
1090 draw_text(a + 1, b, boxnames[numboxes-1-i], 0);
1092 y += scale_box_height + scale_box_skip;
1096 void View::scale_dispatch()
1098 draw_continuous_scale(NULL, !pos_horz);
1103 lspace = rspace = labels_width = 0;
1106 labels_width = scale_fixed_width;
1107 if(labels_width < 0) labels_width = measure_scale_labels();
1108 int space = scale_width + 8 + labels_width + margin;
1110 { lspace = space; scale_x = margin; }
1112 { rspace = space; scale_x = output_width - margin - scale_width; }
1115 scale_y = output_height - margin - scale_height;
1120 center_x = ((double) output_width - 2*margin - lspace - rspace) / 2 + margin + lspace;
1121 center_y = (double) output_height / 2;
1124 void View::show_scale(
bool show)
1134 void View::set_scale_position(
int horz,
int vert)
1145 void View::set_scale_size(
int width,
int height,
int numticks)
1148 scale_width = width;
1149 scale_height = height;
1150 scale_numticks = numticks;
1156 void View::set_scale_format(
const char* fmt)
1159 strncpy(scale_fmt, fmt, 19);
1165 void View::fix_scale_width(
int width)
1168 scale_fixed_width = width;