aboutsummaryrefslogtreecommitdiff
path: root/gragl.c
diff options
context:
space:
mode:
authorNPScript <nathan@reinerweb.ch>2022-08-18 17:04:05 +0200
committerNPScript <nathan@reinerweb.ch>2022-08-18 17:04:05 +0200
commit95361c8c2229840a5e05f49622be629cf654371d (patch)
tree280a6d7706b349563959852057e1741f846d5f60 /gragl.c
first sketch
Diffstat (limited to 'gragl.c')
-rw-r--r--gragl.c198
1 files changed, 198 insertions, 0 deletions
diff --git a/gragl.c b/gragl.c
new file mode 100644
index 0000000..430b581
--- /dev/null
+++ b/gragl.c
@@ -0,0 +1,198 @@
+#include <stdarg.h>
+#include <GL/freeglut.h>
+#include <memory.h>
+#include <stdio.h>
+#include <math.h>
+
+#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);
+}