aboutsummaryrefslogtreecommitdiffstats
path: root/7_2
diff options
context:
space:
mode:
Diffstat (limited to '7_2')
-rw-r--r--7_2/Makefile16
-rw-r--r--7_2/data4
-rw-r--r--7_2/include/common.h32
-rw-r--r--7_2/include/drawable.h42
-rw-r--r--7_2/include/figure.h56
-rw-r--r--7_2/include/input.h24
-rw-r--r--7_2/main.c44
-rw-r--r--7_2/src/drawable.c120
-rw-r--r--7_2/src/figure.c139
-rw-r--r--7_2/src/input.c116
10 files changed, 593 insertions, 0 deletions
diff --git a/7_2/Makefile b/7_2/Makefile
new file mode 100644
index 0000000..7c29431
--- /dev/null
+++ b/7_2/Makefile
@@ -0,0 +1,16 @@
+
+all: main
+
+build:
+ mkdir -p build
+
+build/%.o: src/%.c include/%.h build
+ $(CC) -c -g -ggdb -o $@ $< -Iinclude
+
+main: main.c build/drawable.o build/figure.o build/input.o
+ $(CC) -o $@ $^ -lm -lX11 -Iinclude
+
+.PHONY: clean
+
+clean:
+ $(RM) *.o main build/*
diff --git a/7_2/data b/7_2/data
new file mode 100644
index 0000000..9d831b7
--- /dev/null
+++ b/7_2/data
@@ -0,0 +1,4 @@
+l {0, 1} {1, 2};
+r {2, 2} {40, 18};
+
+c {20, 20} 10;
diff --git a/7_2/include/common.h b/7_2/include/common.h
new file mode 100644
index 0000000..660532f
--- /dev/null
+++ b/7_2/include/common.h
@@ -0,0 +1,32 @@
+#ifndef JAC_COMMON_H
+#define JAC_COMMON_H
+
+/* Для чтающих:
+ * чтобы писать
+ * `vector2 point = { 10, 20 };`
+ * вместо
+ * `struct vector2 point = { 10, 20 };`
+ * (то есть чтобы писать struct перед vector2 было необязательно)
+ * надо объявлять структуру так:
+ * ```
+ * typedef struct {
+ * long x, y;
+ * } vector2;
+ * ```
+ * Таким образом мы объявляем структуру без официального названия,
+ * но присваиваем ей синоним. Чтобы пользоваться и тем, и тем вариантами,
+ * можно сделать так:
+ * ```
+ * typedef struct vector2 {
+ * long x, y;
+ * } vector2;
+ * ```
+ * Так мы и даём ей название, и даём ей синоним.
+ */
+
+// координаты точки в 2-мерном пространстве
+typedef struct vector2 {
+ long x, y;
+} vector2;
+
+#endif // JAC_COMMON_H
diff --git a/7_2/include/drawable.h b/7_2/include/drawable.h
new file mode 100644
index 0000000..3d0caeb
--- /dev/null
+++ b/7_2/include/drawable.h
@@ -0,0 +1,42 @@
+#ifndef JCG_DRAWABLE_H
+#define JCG_DRAWABLE_H
+
+#define FILL_CHR '#'
+#define SPACE_CHR ' '
+
+// что угодно, на чём можно ''нарисовать''
+// должно иметь размер, размер пикселей, данные
+// функция put записывает пиксель по координатам x, y на поле
+// функция show выводит данные на экран/куда угодно ещё
+struct drawable {
+ long x, y, pix_s;
+ void *data;
+ void (*put)(struct drawable *self, long x, long y);
+ void(*show)(const struct drawable *self);
+};
+
+
+// конструктор
+void drawable_init(struct drawable* self,
+ void(*put_f)(struct drawable *, long, long),
+ void(*show_f)(const struct drawable *),
+ long width,
+ long height,
+ long pix_s);
+// деструктор
+void drawable_destroy(struct drawable *self);
+// конструктор для консольного поля
+struct drawable drawable_plaintxt(long width, long height);
+// конструктор для графического поля
+struct drawable drawable_X11(long width, long height);
+
+// put для консольного drawable
+void put_plaintxt(struct drawable *self, long x, long y);
+// show для консольного drawable
+void show_plaintxt(const struct drawable *self);
+// put для графического drawable
+void put_X11(struct drawable *self, long x, long y);
+// show для графического drawable
+void show_X11(const struct drawable *self);
+
+#endif // JCG_DRAWABLE_H
diff --git a/7_2/include/figure.h b/7_2/include/figure.h
new file mode 100644
index 0000000..393ca00
--- /dev/null
+++ b/7_2/include/figure.h
@@ -0,0 +1,56 @@
+#ifndef JCG_FIGURE_H
+#define JCG_FIGURE_H
+
+#include "drawable.h"
+#include "common.h"
+
+// любая фигура
+// создаётся функциями figure_point, figure_line и т.д.
+// у каждой фигуры должен быть способ "нарисоваться" на
+// любое "рисовальное" поле, используя функцию drawable.put
+struct figure {
+ enum {
+ F_NONE, F_POINT, F_RECT, F_LINE, F_CIRCLE
+ } type;
+ union {
+ struct {
+ vector2 coords;
+ } point;
+ struct {
+ vector2 upleft, downright;
+ } rect;
+ struct {
+ vector2 start, end;
+ } line;
+ struct {
+ vector2 center;
+ long rad;
+ } circle;
+ };
+ void (*draw)(const struct figure *self, struct drawable *d);
+};
+
+// массив функций по типам (lookup table)
+extern void (*const draw_lookup[])(const struct figure *, struct drawable *);
+
+// конструктор 1
+struct figure figure_point(vector2 p);
+// конструктор 2
+struct figure figure_rect(vector2 upleft, vector2 downright);
+// конструктор 3
+struct figure figure_line(vector2 start, vector2 end);
+// конструктор 4
+struct figure figure_circle(vector2 center, long radius);
+
+// draw для F_POINT
+void draw_point(const struct figure *self, struct drawable *d);
+// draw для F_RECT
+void draw_rect(const struct figure *self, struct drawable *d);
+// draw для F_LINE
+void draw_line(const struct figure *self, struct drawable *d);
+// draw для F_CIRCLE
+void draw_circle(const struct figure *self, struct drawable *f);
+
+void print_figure(const struct figure *self);
+
+#endif // JCG_FIGURE_H
diff --git a/7_2/include/input.h b/7_2/include/input.h
new file mode 100644
index 0000000..24285b8
--- /dev/null
+++ b/7_2/include/input.h
@@ -0,0 +1,24 @@
+#ifndef JAC_INPUT_H
+#define JAC_INPUT_H
+
+#include "common.h"
+#include "figure.h"
+
+extern void(*settings_handler)(const char *sett_string);
+
+// пропустить пробелы
+void skipw(char const **s);
+// проспустит цифры
+void skipd(char const **s);
+// проерить наличие символа
+char chktok(char const **str, char tok);
+// прочитать число
+char parsel(char const **str, long *l);
+// прочитать вектор из 2 чисел
+char parsev(char const **str, vector2 *v);
+// прочитать одну фигуру
+struct figure read_figure(const char *str);
+// прочитать целый файл
+struct figure *read_file(const char *path);
+
+#endif // JAC_INPUT_H
diff --git a/7_2/main.c b/7_2/main.c
new file mode 100644
index 0000000..5411ecf
--- /dev/null
+++ b/7_2/main.c
@@ -0,0 +1,44 @@
+#include <X11/X.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "input.h"
+#include "drawable.h"
+#include "figure.h"
+
+long fatness = 1; // пока никак не используется
+
+int sx = 100, sy = 100;
+
+int main(int argc, char *argv[]) {
+ char file[256] = {};
+ if (argc >= 2) {
+ size_t len = strlen(argv[1]);
+ memcpy(file, argv[1], len > 255 ? 255 : len);
+ } else {
+ printf("введите файл: ");
+ scanf("%255s", file);
+ }
+ char x11 = 0;
+ for (int i = 0; i < argc; ++i) {
+ if (!strcmp("-X", argv[i])) x11 = 1;
+ }
+ struct figure *fs = read_file(file);
+ struct drawable d = x11 ? drawable_X11(sx, sy) : drawable_plaintxt(sx, sy);
+ if (!fs) {
+ fprintf(stderr, "ERROR: errno %i: %s\n", errno, strerror(errno));
+ return 1;
+ }
+ for (struct figure *i = fs; i->type != F_NONE; ++i)
+ i->draw(i, &d);
+
+ d.show(&d);
+ free(fs);
+ drawable_destroy(&d);
+ return 0;
+}
+
diff --git a/7_2/src/drawable.c b/7_2/src/drawable.c
new file mode 100644
index 0000000..33e7290
--- /dev/null
+++ b/7_2/src/drawable.c
@@ -0,0 +1,120 @@
+#include "drawable.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+static struct {
+ enum {CTX_NO, CTX_INIT, CTX_FAIL} init;
+ Display *d;
+ Window r, w;
+ int s;
+ GC gctx;
+ XVisualInfo v;
+ XImage *i;
+ int* data;
+} X11 = { .init=CTX_NO };
+
+struct drawable drawable_plaintxt(long width, long height) {
+ struct drawable ret;
+ // with, height +1 because inclusive
+ drawable_init(&ret, put_plaintxt, show_plaintxt, width + 1, height + 1, sizeof (char));
+ memset(ret.data, 0, height*width*1);
+ return ret;
+}
+struct drawable drawable_X11(long width, long height) {
+ struct drawable ret;
+ drawable_init(&ret, put_X11, show_X11, width, height, sizeof (int));
+ int* data = ret.data;
+ for (size_t i = 0; i < width*height; ++i)
+ data[i] = 0x00FFFFFF;
+ return ret;
+}
+
+void drawable_init(struct drawable* self,
+ void(*put_f)(struct drawable *, long, long),
+ void(*show_f)(const struct drawable *),
+ long width,
+ long height,
+ long pix_s)
+{
+ self->x = width;
+ self->y = height;
+ self->pix_s = pix_s;
+ self->data = malloc(height*width*pix_s);
+ self->put = put_f;
+ self->show = show_f;
+}
+
+void drawable_destroy(struct drawable *self) {
+ free(self->data);
+}
+
+/// plaintxt methods ///
+
+void put_plaintxt(struct drawable *self, long x, long y) {
+ if (x >= self->x || y >= self->y || x < 0 || y < 0) return;
+ char *data = self->data;
+ data[self->x * y + x] = 1;
+}
+
+void show_plaintxt(const struct drawable *self) {
+ char map[2] = {SPACE_CHR, FILL_CHR};
+ for (int i = 0; i < self->y; ++i) {
+ for (int j = 0; j < self->x; ++j) {
+ char *d = self->data;
+ putchar(map[d[i*self->x + j]]);
+ }
+ putchar('\n');
+ }
+}
+
+
+/// X11 from now on ///
+
+static void init_X11(const struct drawable *self) {
+ X11.d = XOpenDisplay(NULL);
+ if (X11.d == NULL) {
+ X11.init = CTX_FAIL;
+ return;
+ }
+ X11.s = DefaultScreen(X11.d);
+ X11.r = RootWindow(X11.d, X11.s);
+ X11.gctx = DefaultGC(X11.d, X11.s);
+ Window w = XCreateSimpleWindow(X11.d, X11.r, 0, 0, self->x, self->y, 0, 0, 0x00FFFFFF);
+ if (!XMatchVisualInfo(X11.d, X11.s, 24, TrueColor, &X11.v)) {
+ XDestroyWindow(X11.d, X11.w);
+ XCloseDisplay(X11.d);
+ X11.init = CTX_FAIL;
+ return;
+ };
+ XMapWindow(X11.d, X11.w);
+ XSelectInput(X11.d, X11.w, ExposureMask);
+ X11.data = malloc(self->x * self->y * sizeof (int));
+ X11.i = XCreateImage(X11.d, X11.v.visual, X11.v.depth, ZPixmap, 0, (void*)X11.data, self->x, self->y, 8*sizeof (int), 0);
+}
+
+void put_X11(struct drawable *self, long x, long y) {
+ if (x >= self->x || y >= self->y || x < 0 || y < 0) return;
+ int *data = self->data;
+ data[self->x * y + x] = 0x00000000;
+}
+
+void show_X11(const struct drawable *self) {
+start:
+ switch (X11.init) {
+ case CTX_NO: init_X11(self); goto start;
+ case CTX_INIT: break;
+ case CTX_FAIL:
+ fprintf(stderr, "Error: Could not initialize Xlib\n");
+ return;
+ }
+ XEvent e = {};
+ XNextEvent(X11.d, &e);
+ XPutImage(X11.d, X11.w, X11.gctx, X11.i, 0, 0, 0, 0, self->x, self->y);
+}
+
diff --git a/7_2/src/figure.c b/7_2/src/figure.c
new file mode 100644
index 0000000..290d4af
--- /dev/null
+++ b/7_2/src/figure.c
@@ -0,0 +1,139 @@
+
+#include "figure.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+void (*const draw_lookup[])(const struct figure *, struct drawable *) = {
+ [F_NONE] = NULL,
+ [F_POINT] = draw_point,
+ [F_RECT] = draw_rect,
+ [F_LINE] = draw_line,
+ [F_CIRCLE] = draw_circle
+};
+
+void swapl(long *x, long *y) {
+ long tmp = *x;
+ *x = *y;
+ *y = tmp;
+}
+
+struct figure figure_point(vector2 p) {
+ return (struct figure) {
+ .type = F_POINT,
+ .point.coords = p,
+ .draw = draw_point
+ };
+}
+
+struct figure figure_rect(vector2 upleft, vector2 downright) {
+ return (struct figure) {
+ .type = F_RECT,
+ .rect = {upleft, downright},
+ .draw = draw_rect
+ };
+}
+
+struct figure figure_line(vector2 start, vector2 end) {
+ return (struct figure) {
+ .type = F_LINE,
+ .line = {start, end},
+ .draw = draw_line
+ };
+}
+
+struct figure figure_circle(vector2 center, long radius) {
+ return (struct figure) {
+ .type = F_CIRCLE,
+ .circle = {center, radius},
+ .draw = draw_circle
+ };
+}
+
+
+void draw_point(const struct figure *self, struct drawable *d) {
+ d->put(d, self->point.coords.x, self->point.coords.y);
+}
+
+void draw_rect(const struct figure *self, struct drawable *d) {
+ vector2 upleft = self->rect.upleft;
+ vector2 downright = self->rect.downright;
+ for (long i = upleft.x; i < downright.x + 1; ++i) {
+ d->put(d, i, upleft.y);
+ d->put(d, i, downright.y);
+ }
+ for (long j = upleft.y + 1; j < downright.y; ++j) {
+ d->put(d, upleft.x, j);
+ d->put(d, downright.x, j);
+ }
+}
+
+void draw_line(const struct figure *self, struct drawable *d) {
+ vector2 start = self->line.start;
+ vector2 end = self->line.end;
+ char gt45 = labs(end.y - start.y) > labs(end.x - start.x);
+ long x0 = start.x, y0 = start.y,
+ x1 = end.x, y1 = end.y;
+ if (gt45) {
+ swapl(&x0, &y0);
+ swapl(&x1, &y1);
+ }
+ if (x0 > x1) {
+ swapl(&x0, &x1);
+ swapl(&y0, &y1);
+ }
+ long dy = labs(y1-y0),
+ dx = x1 - x0,
+ err = dx >> 1, // *2
+ yinc = (y1 > y0 ? 1 : -1);
+
+ for (long x = x0, y = y0; x <= x1; ++x) {
+ if (gt45) d->put(d, y, x);
+ else d->put(d, x, y);
+ err -= dy;
+ if (err < 0) {
+ y += yinc;
+ err += dx;
+ }
+ }
+}
+
+void draw_circle(const struct figure *self, struct drawable *f) {
+ const vector2 p = self->circle.center;
+ const long rad = self->circle.rad - 1;
+ const long pi4 = ceil(M_SQRT1_2 * rad);
+ long x0 = 0, y0 = rad;
+ do {
+ // выглядит коряво, зато в 8 раз меньше повторений цикла
+ f->put(f, p.x-x0, p.y-y0); // 3 четверть
+ f->put(f, p.x-x0, p.y+y0); // 2 чет.
+ f->put(f, p.x+x0, p.y-y0); // 4 ч.
+ f->put(f, p.x+x0, p.y+y0); // 1 ч
+ f->put(f, p.x-y0, p.y-x0);
+ f->put(f, p.x-y0, p.y+x0);
+ f->put(f, p.x+y0, p.y-x0);
+ f->put(f, p.x+y0, p.y+x0);
+ ++x0;
+ // вычисляем x^2 + (y+1/2)^2 - r^2
+ // раскрыли скобки и умножили на 4, чтобы не иметь дело
+ // с дробными числами (они медленные)
+ long func = 4*x0*x0 + 4*y0*y0 - 4*y0 + 1 - 4*rad*rad;
+ y0 = (func >= 0 ? y0 - 1 : y0);
+ } while (x0 < pi4);
+}
+
+void print_figure(const struct figure *self) {
+ printf("figure {\n\t.type = %i\n\t{%li, %li},\n\t", self->type, self->line.start.x, self->line.start.y);
+ switch (self->type) {
+ case F_LINE:
+ case F_RECT:
+ printf("{%li, %li}\n\t", self->line.end.x, self->line.end.y);
+ break;
+ case F_CIRCLE:
+ printf("%li\n\t", self->circle.rad);
+ // fallthrough
+ case F_NONE:
+ case F_POINT:;
+ }
+ printf(".draw = %p\n}\n", self->draw);
+}
diff --git a/7_2/src/input.c b/7_2/src/input.c
new file mode 100644
index 0000000..d2dca7c
--- /dev/null
+++ b/7_2/src/input.c
@@ -0,0 +1,116 @@
+#include "input.h"
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *const unexpchtok = "Unexpected token: %c\n";
+const char *const invalidint = "Invalid integer: %s\n";
+
+#define error(fmt, ...) do { \
+ fprintf(stderr, fmt, __VA_ARGS__); \
+ return 0; \
+} while(0)
+
+#define maybe_realloc(size, cap, pointer, type) do { \
+ if (size >= cap) { \
+ cap <<= 1; \
+ pointer = realloc(pointer, cap * sizeof (type));\
+ } \
+} while(0)
+
+void(*settings_handler)(const char*) = NULL;
+
+void skipw(char const **s) { while(isspace(**s)) ++*s; }
+void skipd(char const **s) { while(isdigit(**s)) ++*s; }
+
+char chktok(char const **str, char tok) {
+ skipw(str);
+ long tmp = atol(*str);
+ if (**str != tok) error(unexpchtok, **str);
+ ++*str;
+ return 1;
+}
+
+char parsel(char const **str, long *l) {
+ skipw(str);
+ long tmp = atoi(*str);
+ if (tmp == 0 && **str != '0') error(invalidint, *str);
+ *l = tmp;
+ skipd(str);
+ return 1;
+}
+
+char parsev(char const **str, vector2 *v) {
+ long x, y;
+ // я ща кончу на этот код
+ char suc = chktok(str, '{')
+ && parsel(str, &x)
+ && chktok(str, ',')
+ && parsel(str, &y)
+ && chktok(str, '}');
+ if (suc) {
+ v->x = x;
+ v->y = y;
+ return 1;
+ } else return 0;
+}
+
+struct figure read_figure(const char *str) {
+ struct figure ret = {.type = F_NONE};
+ const char *strp = str;
+ skipw(&strp);
+ ++strp;
+ switch(strp[-1]) {
+ case '.': {
+ if (settings_handler != NULL) settings_handler(strp);
+ } break;
+ case 'p': {
+ if (parsev(&strp, &ret.point.coords)
+ && chktok(&strp, ';')) ret.type = F_POINT;
+ } break;
+ case 'r': {
+ if (parsev(&strp, &ret.rect.upleft)
+ && parsev(&strp, &ret.rect.downright)
+ && chktok(&strp, ';')) ret.type = F_RECT;
+ } break;
+ case 'l': {
+ if (parsev(&strp, &ret.line.start)
+ && parsev(&strp, &ret.line.end)
+ && chktok(&strp, ';')) ret.type = F_LINE;
+ } break;
+ case 'c': {
+ if (parsev(&strp, &ret.circle.center)
+ && parsel(&strp, &ret.circle.rad)
+ && chktok(&strp, ';')) ret.type = F_CIRCLE;
+ } break;
+ default:;
+ }
+ ret.draw = draw_lookup[ret.type];
+ return ret;
+}
+
+struct figure *read_file(const char *path) {
+ FILE *f = fopen(path, "r");
+ if (!f) return NULL;
+ size_t bs = 1024;
+ size_t fs = -1, fcap = 16;
+ char *buf = malloc(fcap * sizeof(struct figure));
+ struct figure *figures = malloc(fcap * sizeof (struct figure));
+ while (!feof(f)) {
+ if (getdelim(&buf, &bs, ';', f) < 0) break;
+ struct figure f = read_figure(buf);
+ if (f.type == F_NONE) continue;
+ ++fs;
+ maybe_realloc(fs, fcap, figures, struct figure);
+ memcpy(figures + fs, &f, sizeof (struct figure));
+ }
+ ++fs;
+ maybe_realloc(fs, fcap, figures, struct figure);
+ struct figure END = {.type = F_NONE, 0};
+ memcpy(figures + fs, &END, sizeof (struct figure));
+ free(buf);
+ return figures;
+}
+