#include #include #include #include #include #include "gragl.h" #define SUBWINDOWS 64 Plot2dGroup * target = NULL; int subwindows[SUBWINDOWS]; static void enable_multi_sample() { glEnable(GL_MULTISAMPLE); glHint(GL_MULTISAMPLE_FILTER_HINT_NV, GL_NICEST); } static void draw_function(double from, double to, double step, Scalar(*fun)(double)) { glColor3f(0.9f, 0.5f, 0.2f); glLineWidth(2); glBegin(GL_LINES); for (double i = from; i < to; i += step) { Scalar current = fun(i); Scalar next = fun(i + step); if (current.valid) { glVertex2f(i, current.v); glVertex2f(i + step, next.v); } } glEnd(); } void draw_axis() { glColor3f(1, 1, 1); glLineWidth(2); glBegin(GL_LINES); glVertex2f(0, 0); glVertex2f(1, 0); glVertex2f(0, 0); glVertex2f(0, 1); glVertex2f(1, 0); glVertex2f(0.9, 0.1); glVertex2f(1, 0); glVertex2f(0.9, -0.1); glVertex2f(0, 1); glVertex2f(0.1, 0.9); glVertex2f(0, 1); glVertex2f(-0.1, 0.9); glEnd(); } void draw_grid(double from, double to) { glColor3f(0.2, 0.2, 0.2); double yl = (from + to) / 2 + 1; glLineWidth(2); glBegin(GL_LINES); for (double i = from; i < to; ++i) { glVertex2f(i, yl); glVertex2f(i, -yl); } for (double i = -yl; i < yl; ++i) { glVertex2f(from, i); glVertex2f(to, i); } glEnd(); glColor3f(0.5, 0.5, 0.5); glBegin(GL_LINES); glVertex2f(from, 0); glVertex2f(to, 0); glVertex2f(0, yl); glVertex2f(0, -yl); glEnd(); glColor3f(0.7, 0.7, 0.7); glBegin(GL_LINE_LOOP); glVertex2f(from, yl); glVertex2f(to, yl); glVertex2f(to, -yl); glVertex2f(from, -yl); glEnd(); } static void update() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); int window = glutGetWindow(); int plot_id = 0; while (subwindows[plot_id] != window) ++plot_id; Plot2d * plot = &(target->plots[plot_id]); double translate = -((plot->to + plot->from) / 2); double zoom = 2 / (plot->to - plot->from); glScalef(zoom, zoom, zoom); glTranslatef(translate, 0, 0); draw_grid(plot->from, plot->to); draw_axis(); draw_function(plot->from, plot->to, plot->step, plot->func); glTranslatef(-translate, 0, 0); glScalef(1/zoom, 1/zoom, 1/zoom); glutSwapBuffers(); } static void parent_update() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glutSwapBuffers(); int width = glutGet(GLUT_WINDOW_WIDTH); int height = glutGet(GLUT_WINDOW_HEIGHT); int min = width > height ? height : width; unsigned n_plots = ((unsigned)sqrt(target->n)); int plot_dim = min / (int)n_plots - (int)target->padding / 4; plot_dim = plot < 0 ? 1 : plot_dim; for (unsigned i = 0; i < SUBWINDOWS && subwindows[i] > 0; ++i) { glutSetWindow(subwindows[i]); glutReshapeWindow( plot_dim - target->padding / 2, plot_dim - target->padding / 2 ); glutPositionWindow( (i % n_plots) * plot_dim + target->padding / 2, (i / n_plots) * plot_dim + target->padding / 2 ); } } void plot(Plot2dGroup * group) { target = group; char * arg[1] = { "" }; int argc = 1; glutInit(&argc, arg); glutInitWindowSize(500, 500); glutSetOption(GLUT_MULTISAMPLE, 8); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE); int parent = glutCreateWindow("GRAGL"); for (int i = 0; i < group->n; ++i) { int id = glutCreateSubWindow(parent, 1, 1, 1, 1); subwindows[i] = id; glutSetWindow(id); glutDisplayFunc(update); } glutSetWindow(parent); glutDisplayFunc(parent_update); enable_multi_sample(); glutMainLoop(); } Plot2dGroup * create_plot2d_group(int num_args, ...) { Plot2dGroup * group = (Plot2dGroup*)malloc(sizeof(Plot2dGroup)); group->plots = (Plot2d*)malloc(sizeof(Plot2d) * num_args); group->n = num_args; group->padding = 20; va_list ap; va_start(ap, num_args); for (int i = 0; i < num_args; ++i) { group->plots[i] = va_arg(ap, Plot2d); } va_end(ap); return group; } void free_plot2d_group(Plot2dGroup * group) { free(group->plots); free(group); }