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;
167 str <<
" >>" << std::endl;
175 default:
throw Hermes::Exceptions::Exception(
"Unknown wait event");
break;
181 bool do_refresh =
true;
195 double mesh_height = vertices_max_y - vertices_min_y;
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;
208 trans_x = -scale * (vertices_min_x + vertices_max_x) / 2;
209 trans_y = -scale * (vertices_min_y + vertices_max_y) / 2;
215 void View::on_create(
int output_id)
218 this->output_id = output_id;
220 set_palette_filter(pal_filter == GL_LINEAR);
223 void View::on_close()
232 glClearColor(1.0, 1.0, 1.0, 0.0);
233 glClear(GL_COLOR_BUFFER_BIT);
236 void View::pre_display()
252 display_antialiased();
256 if (b_help) draw_help();
257 else if (b_scale) scale_dispatch();
268 glReadBuffer(GL_BACK_LEFT);
269 save_screenshot_internal(screenshot_filename.c_str());
270 want_screenshot =
false;
281 static float jitter16[16][2] =
283 { 0.4375, 0.4375 }, { 0.1875, 0.5625 },
284 { 0.9375, 1.1875 }, { 0.4375, 0.9375 - 1 },
285 { 0.6875, 0.5625 }, { 0.1875, 0.0625 },
286 { 0.6875, 0.3125 }, { 0.1875, 0.3125 },
287 { 0.4375, 0.1875 }, { 0.9375 - 1, 0.4375 },
288 { 0.6875, 0.8125 }, { 0.4375, 0.6875 },
289 { 0.6875, 0.0625 }, { 0.9375, 0.9375 },
290 { 1.1875, 0.8125 }, { 0.9375, 0.6875 }
293 void View::display_antialiased()
295 glClear(GL_ACCUM_BUFFER_BIT);
296 for (
int i = 0; i < 16; i++)
298 jitter_x = jitter16[i][0];
299 jitter_y = jitter16[i][1];
300 set_ortho_projection();
303 glAccum(GL_ACCUM, 1.0 / 16);
305 glAccum(GL_RETURN, 1.0);
306 jitter_x = jitter_y = 0.0;
309 void View::set_ortho_projection(
bool no_jitter)
311 double jx = no_jitter ? 0.0 : jitter_x;
312 double jy = no_jitter ? 0.0 : jitter_y;
314 glMatrixMode(GL_PROJECTION);
316 glOrtho(jx, output_width + jx, output_height - 1 + jy, -1 + jy, -10, 10);
318 glMatrixMode(GL_MODELVIEW);
322 void View::set_3d_projection(
int fov,
double znear,
double zfar)
324 double top = znear * tan((
double)fov / 2.0 / 180.0 * M_PI);
325 double right = (double)output_width / output_height * top;
326 double left = -right;
327 double bottom = -top;
328 double offsx = (right - left) / output_width * jitter_x;
329 double offsy = (top - bottom) / output_height * jitter_y;
331 glMatrixMode(GL_PROJECTION);
333 glFrustum(left - offsx, right - offsx, bottom - offsy, top - offsy, znear, zfar);
339 double frame_time_sum = 0;
340 for (
int i = 0; i < FPS_FRAME_SIZE; i++)
344 unsigned char buffer[128];
345 sprintf((
char*)buffer,
"avg. frame: %.1f ms", (
float)(frame_time_sum / FPS_FRAME_SIZE));
348 void* font = GLUT_BITMAP_HELVETICA_10;
349 int width_px = glutBitmapLength(font, buffer);
350 int height_px = glutBitmapHeight(font);
351 int edge_thickness = 2;
352 set_ortho_projection(
false);
356 glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
358 glColor4f(1.0f, 1.0f, 1.0f, 0.5f);
359 glVertex2i(output_width - (width_px + 2 * edge_thickness), 0);
360 glVertex2i(output_width, 0);
361 glVertex2i(output_width, height_px + 2 * edge_thickness);
362 glVertex2i(output_width - (width_px + 2 * edge_thickness), height_px + 2 * edge_thickness);
367 glColor3f(1.0f, 0.0f, 0.0f);
368 glRasterPos2i(output_width - (width_px + edge_thickness), edge_thickness + height_px);
370 glutBitmapString(font, buffer);
373 void View::on_reshape(
int width,
int height)
375 glViewport(0, 0, width, height);
377 output_width = width;
378 output_height = height;
382 void View::on_mouse_move(
int x,
int y)
386 trans_x += (x - mouse_x);
387 trans_y += (mouse_y - y);
392 log_scale += (mouse_y - y);
394 trans_x = scx - objx * scale - center_x;
395 trans_y = center_y - objy * scale - scy;
398 else if (scale_dragging)
400 int oldv = pos_vert, oldh = pos_horz;
401 pos_horz = (x > output_width / 2);
402 pos_vert = (y < output_height / 2);
403 if (pos_horz != oldh || pos_vert != oldv)
411 bool oldf = scale_focused;
412 scale_focused = (x >= scale_x && x <= scale_x + scale_width &&
413 y >= scale_y && y <= scale_y + scale_height);
414 if (oldf != scale_focused)
421 void View::on_left_mouse_down(
int x,
int y)
424 scale_dragging =
true;
432 void View::on_left_mouse_up(
int x,
int y)
434 scaling = dragging = scale_dragging =
false;
438 void View::on_right_mouse_down(
int x,
int y)
444 objx = (x - center_x - trans_x) / scale;
445 objy = (center_y - y - trans_y) / scale;
450 void View::on_right_mouse_up(
int x,
int y)
452 scaling = dragging =
false;
455 void View::on_key_down(
unsigned char key,
int x,
int y)
457 const char *file_name =
nullptr;
477 const char *file_name = get_screenshot_file_name();
478 glReadBuffer(GL_FRONT_LEFT);
479 save_screenshot_internal(file_name);
490 default:
throw Hermes::Exceptions::Exception(
"Invalid palette type");
505 void View::on_special_key(
int key,
int x,
int y)
521 void View::wait_for_close()
529 void View::wait_for_draw()
532 if (output_id >= 0 && !frame_ready)
540 LARGE_INTEGER freq, ticks;
541 QueryPerformanceFrequency(&freq);
542 QueryPerformanceCounter(&ticks);
543 return (1000.0 * (
double)ticks.QuadPart) / (double)freq.QuadPart;
546 gettimeofday(&tv,
nullptr);
547 return (
double)tv.tv_sec * 1000 + (double)tv.tv_usec / 1000;
553 return this->title.c_str();
558 char* text_contents = malloc_with_check<char>(BUF_SZ);
562 va_start(arglist, msg);
563 vsprintf(text_contents, msg, arglist);
566 bool do_set_title =
true;
569 this->title = text_contents;
574 do_set_title =
false;
581 free_with_check(text_contents);
588 if (x < 0.0) x = 0.0;
589 else if (x > 1.0) x = 1.0;
590 x *= num_pal_entries;
592 gl_color[0] = palette_data[n][0];
593 gl_color[1] = palette_data[n][1];
594 gl_color[2] = palette_data[n][2];
597 gl_color[0] = gl_color[1] = gl_color[2] = (float)x;
599 gl_color[0] = gl_color[1] = gl_color[2] = (float)(1.0 - x);
601 gl_color[0] = gl_color[1] = gl_color[2] = 1.0f;
604 void View::set_num_palette_steps(
int num)
606 if (num < 2) num = 2;
607 if (num > 256) num = 256;
622 unsigned char palette[256][3];
623 for (i = 0; i < pal_steps; i++)
627 palette[i][0] = (
unsigned char)(gl_color[0] * 255);
628 palette[i][1] = (
unsigned char)(gl_color[1] * 255);
629 palette[i][2] = (
unsigned char)(gl_color[2] * 255);
631 for (i = pal_steps; i < 256; i++)
632 memcpy(palette[i], palette[pal_steps - 1], 3);
637 glTexImage1D(GL_TEXTURE_1D, 0, 3, 256, 0, GL_RGB, GL_UNSIGNED_BYTE, palette);
638 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
639 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
642 void View::set_palette_filter(
bool linear)
647 pal_filter = linear ? GL_LINEAR : GL_NEAREST;
652 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, pal_filter);
653 glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, pal_filter);
674 void View::update_tex_adjust()
676 if (pal_filter == GL_LINEAR)
678 tex_scale = (double)(pal_steps - 1) / 256.0;
679 tex_shift = 0.5 / 256.0;
683 tex_scale = (double)pal_steps / 256.0;
688 void View::set_min_max_range(
double min,
double max)
693 this->warn(
"Upper bound set below the lower bound: reversing to (%f, %f).", min, max);
705 void View::auto_min_max_range()
716 void View::get_min_max_range(
double& min,
double& max)
724 void View::draw_text(
double x,
double y,
const char* text,
int align)
726 void* font = GLUT_BITMAP_9_BY_15;
729 int width = glutBitmapLength(font, (
const unsigned char*)text);
731 if (align == 1) x -= width;
733 else x -= (double)width / 2;
738 glDisable(GL_TEXTURE_1D);
739 glDisable(GL_LIGHTING);
741 glRasterPos2d((
int)(x + 0.5), (
int)(y + 0.5));
742 glutBitmapString(font, (
const unsigned char*)text);
745 int View::get_text_width(
const char* text)
747 void* font = GLUT_BITMAP_9_BY_15;
748 return glutBitmapLength(font, (
const unsigned char*)text);
751 void View::draw_help()
754 set_ortho_projection(
true);
755 glDisable(GL_DEPTH_TEST);
756 glDisable(GL_LIGHTING);
757 glDisable(GL_TEXTURE_1D);
758 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
760 const char* text = get_help_text();
763 for (
const char* p = text; *p; p++)
766 int width = get_text_width(text);
767 int height = n * glutBitmapHeight(GLUT_BITMAP_9_BY_15);
768 int x = 10, y = 10, b = 6;
771 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
772 glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
774 glVertex2d(x, y + height + 2 * b);
775 glVertex2d(x + width + 2 * b, y + height + 2 * b);
776 glVertex2d(x + width + 2 * b, y);
782 draw_text(x + b, y + b + 7, text);
787 char* View::get_screenshot_file_name()
789 static char file_name[1024] = { 0 };
790 bool got_file_name =
false;
793 sprintf(file_name,
"screen%03d.bmp", screenshot_no);
794 FILE *f = fopen(file_name,
"r");
796 got_file_name =
true;
800 }
while (!got_file_name);
804 typedef unsigned int dword;
805 typedef unsigned short word;
807 const word BITMAP_ID = 0x4D42;
835 void View::save_screenshot_internal(
const char *file_name)
841 char* pixels = malloc_with_check_direct_size<char>(4 * output_width * output_height);
845 glReadPixels(0, 0, output_width, output_height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
848 glReadPixels(0, 0, output_width, output_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
849 this->warn(
"BGRA format not supported. Saved image will have inverted colors");
852 FILE* file = fopen(file_name,
"wb");
854 throw Hermes::Exceptions::Exception(
"Could not open '%s' for writing", file_name);
857 file_header.type = BITMAP_ID;
859 4 * output_width * output_height;
860 file_header.reserved1 = file_header.reserved2 = 0;
862 file_header.off_bits = 14 + 40;
864 if (fwrite(&file_header,
sizeof(file_header), 1, file) != 1)
867 throw Hermes::Exceptions::Exception(
"Error writing bitmap header");
871 info_header.size =
sizeof(BitmapInfoHeader);
872 info_header.width = output_width;
873 info_header.height = output_height;
874 info_header.planes = 1;
876 info_header.bit_count = 32;
877 info_header.compression = 0;
878 info_header.size_image = output_width * output_height * 4;
880 info_header.xdpi = 2835;
882 info_header.ydpi = 2835;
883 info_header.clr_used = 0;
884 info_header.clr_important = 0;
886 if (fwrite(&info_header,
sizeof(info_header), 1, file) != 1)
889 throw Hermes::Exceptions::Exception(
"Error writing bitmap header");
893 if (fwrite((GLubyte*)pixels, 1, info_header.size_image, file) != info_header.size_image)
896 throw Hermes::Exceptions::Exception(
"Error writing pixel data");
901 printf(
"Image \"%s\" saved.\n", file_name);
907 if (output_id >= 0) {
908 hq_frame = high_quality;
909 want_screenshot =
true;
910 screenshot_filename = bmpname;
921 sprintf(buffer, format, number);
925 int View::measure_scale_labels()
928 for (
int i = 0; i <= scale_numticks + 1; i++)
930 double value = range_min + (double)i * (range_max - range_min) / (scale_numticks + 1);
931 if (fabs(value) < Hermes::HermesEpsilon) value = 0.0;
933 sprintf(text, scale_fmt, value);
934 int w = get_text_width(text);
935 if (w > result) result = w;
940 void View::draw_continuous_scale(
char* title,
bool righttext)
943 double y0 = scale_y + scale_height;
945 set_ortho_projection(
true);
946 glDisable(GL_DEPTH_TEST);
947 glDisable(GL_LIGHTING);
948 glDisable(GL_TEXTURE_1D);
949 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
954 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
955 glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
956 int rt = righttext ? 0 : labels_width + 8;
958 glVertex2d(scale_x - b - rt, y0 + 5 + b);
959 glVertex2d(scale_x + scale_width + 8 + labels_width + b - rt, y0 + 5 + b);
960 glVertex2d(scale_x + scale_width + 8 + labels_width + b - rt, scale_y - 5 - b);
961 glVertex2d(scale_x - b - rt, scale_y - 5 - b);
966 glColor3f(0.0f, 0.0f, 0.0f);
968 glVertex2d(scale_x, scale_y);
969 glVertex2d(scale_x, scale_y + scale_height + 1);
970 glVertex2d(scale_x + scale_width + 1, scale_y + scale_height + 1);
971 glVertex2d(scale_x + scale_width + 1, scale_y);
974 glEnable(GL_TEXTURE_1D);
976 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
978 glTexCoord1d(tex_scale + tex_shift);
979 glVertex2d(scale_x + 1, scale_y + 1);
980 glVertex2d(scale_x + scale_width, scale_y + 1);
981 glTexCoord1d(tex_shift);
982 glVertex2d(scale_x + scale_width, scale_y + scale_height);
983 glVertex2d(scale_x + 1, scale_y + scale_height);
987 glDisable(GL_TEXTURE_1D);
991 glColor4f(1.0f, 1.0f, 1.0f, 0.3f);
993 glVertex2d(scale_x + 1, scale_y + 1);
994 glVertex2d(scale_x + scale_width, scale_y + 1);
995 glVertex2d(scale_x + scale_width, scale_y + scale_height);
996 glVertex2d(scale_x + 1, scale_y + scale_height);
1002 glDisable(GL_BLEND);
1003 glDisable(GL_LINE_STIPPLE);
1006 for (i = 0; i < scale_numticks; i++)
1008 y0 = scale_y + scale_height - (double)(i + 1) * scale_height / (scale_numticks + 1);
1009 glVertex2d(scale_x, y0);
1010 glVertex2d(scale_x + 0.2 * scale_width + 1, y0);
1011 glVertex2d(scale_x + 0.8 * scale_width, y0);
1012 glVertex2d(scale_x + scale_width, y0);
1017 for (i = 0; i <= scale_numticks + 1; i++)
1019 double value = range_min + (double)i * (range_max - range_min) / (scale_numticks + 1);
1020 if (fabs(value) < Hermes::HermesEpsilon) value = 0.0;
1022 sprintf(text, scale_fmt, value);
1023 y0 = scale_y + scale_height - (double)i * scale_height / (scale_numticks + 1);
1025 draw_text(scale_x + scale_width + 8, y0, text);
1027 draw_text(scale_x - 8, y0, text, 1);
1031 void View::draw_discrete_scale(
int numboxes,
const char* boxnames[],
const float boxcolors[][3])
1033 set_ortho_projection(
true);
1034 glDisable(GL_DEPTH_TEST);
1035 glDisable(GL_LIGHTING);
1036 glDisable(GL_TEXTURE_1D);
1037 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1042 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1043 glColor4f(1.0f, 1.0f, 1.0f, 0.65f);
1045 glVertex2d(scale_x - b, scale_y - b);
1046 glVertex2d(scale_x - b, scale_y + scale_height + b + 1);
1047 glVertex2d(scale_x + scale_width + b + 1, scale_y + scale_height + b + 1);
1048 glVertex2d(scale_x + scale_width + b + 1, scale_y - b);
1052 glDisable(GL_BLEND);
1054 for (
int i = 0; i < numboxes; i++)
1056 glColor3f(0.0, 0.0, 0.0);
1058 glVertex2d(scale_x, y);
1059 glVertex2d(scale_x, y + scale_box_height + 1);
1060 glVertex2d(scale_x + scale_width + 1, y + scale_box_height + 1);
1061 glVertex2d(scale_x + scale_width + 1, y);
1064 const float* color = boxcolors[numboxes - 1 - i];
1065 float bcolor[3] = { color[0], color[1], color[2] };
1068 bcolor[0] = color[0] * 0.7f + 1.0f*0.3f;
1069 bcolor[1] = color[1] * 0.7f + 1.0f*0.3f;
1070 bcolor[2] = color[2] * 0.7f + 1.0f*0.3f;
1073 glColor3f(bcolor[0], bcolor[1], bcolor[2]);
1075 glVertex2d(scale_x + 1, y + 1);
1076 glVertex2d(scale_x + 1, y + scale_box_height);
1077 glVertex2d(scale_x + scale_width, y + scale_box_height);
1078 glVertex2d(scale_x + scale_width, y + 1);
1081 if ((color[0] + color[1] + color[2]) / 3 > 0.5)
1086 int a = scale_x + scale_width / 2;
1087 int b = y + scale_box_height / 2;
1088 draw_text(a, b, boxnames[numboxes - 1 - i], 0);
1089 draw_text(a + 1, b, boxnames[numboxes - 1 - i], 0);
1091 y += scale_box_height + scale_box_skip;
1095 void View::scale_dispatch()
1097 draw_continuous_scale(
nullptr, !pos_horz);
1102 lspace = rspace = labels_width = 0;
1105 labels_width = scale_fixed_width;
1106 if (labels_width < 0) labels_width = measure_scale_labels();
1107 int space = scale_width + 8 + labels_width + margin;
1110 lspace = space; scale_x = margin;
1114 rspace = space; scale_x = output_width - margin - scale_width;
1118 scale_y = output_height - margin - scale_height;
1123 center_x = ((double)output_width - 2 * margin - lspace - rspace) / 2 + margin + lspace;
1124 center_y = (double)output_height / 2;
1127 void View::show_scale(
bool show)
1137 void View::set_scale_position(
int horz,
int vert)
1148 void View::set_scale_size(
int width,
int height,
int numticks)
1151 scale_width = width;
1152 scale_height = height;
1153 scale_numticks = numticks;
1159 void View::set_scale_format(
const char* fmt)
1162 strncpy(scale_fmt, fmt, 19);
1168 void View::fix_scale_width(
int width)
1171 scale_fixed_width = width;
void refresh_view(int view_id)
Forces redisplay of a view.
void set_title(const char *msg,...)
Changes the window name (in its title-bar) to 'title'.
virtual void update_layout()
Updates layout, i.e., centers mesh.
void remove_view(int view_id)
Removes a view.
void save_numbered_screenshot(const char *format, int number, bool high_quality=false)
void create_gl_palette()
Creates pallete texture in OpenGL. Assumes that view_sync is locked.
#define H2DV_SCALE_LOG_BASE
Base of the scale coefficient. Scale = base^{mouse move}.
double rendering_frames[FPS_FRAME_SIZE]
time spend in rendering of frames[in ms]
unsigned int gl_pallete_tex_id
OpenGL texture object ID.
Wait for all windows to close.
void signal_drawing_finished()
signals drawing finished inside a protected section
Common definitions for Hermes2D.
virtual void get_palette_color(double x, float *gl_color)
Fills gl_color with palette color. Assumes that gl_color points to a vector of three components (RGB)...
virtual void reset_view(bool force_reset)
Resets view based on the axis-aligned bounding box of the mesh. Assumes that the bounding box is set ...
::xsd::cxx::tree::buffer< char > buffer
Binary buffer type.
ViewWaitEvent
Wait events.
::xsd::cxx::tree::type type
C++ type corresponding to the anyType XML Schema built-in type.
virtual void clear_background()
Clears background.
bool view_not_reset
True if the view was not reset and therefore it has to be.
void leave()
leaves protected section
File containing View abstract class.
ViewPaletteType
View palette type.
void wait_close()
waits for close inside a protected section
void enter()
enters protected section
void draw_fps()
draws current FPS
static void wait(const char *text)
Closes all views at once.
const char * get_title() const
Returns the title.
ViewMonitor view_sync
synchronization between all views. Used to access OpenGL and signal a window close event and a keypre...
void wait_drawing_fisnihed()
waits for drawing finished inside a protected section
int rendering_frames_top
the new_ location of the next FPS
void save_screenshot(const char *bmpname, bool high_quality=false)
int add_view(View *view, int x, int y, int width, int height, const char *title)
Adds a view.
void wait_for_any_key(const char *text)
Waits for a keypress which is not processed.
void signal_keypress()
signals keypress inside a protected section
static void wait_for_keypress(const char *text=nullptr)
Waits for keypress. Deprecated.
static double get_tick_count()
returns a current time[in ms]
void refresh()
Refreshes views.
Wait for any unprocessed keypress to happen.
A palette based on hue scale.
void wait_for_all_views_close(const char *text)
Forces view thread to shutdown.
void set_view_title(int view_id, const char *title)
Sets title of a view.
double vertices_min_x
AABB of shown mesh.