aboutsummaryrefslogtreecommitdiffstats
path: root/7_2/src
diff options
context:
space:
mode:
authorjustanothercatgirl <sotov2070@gmail.com>2024-10-17 17:38:07 +0300
committerjustanothercatgirl <sotov2070@gmail.com>2024-10-17 17:38:07 +0300
commit82ec99f51b2b3b7a7b36b43b22df07ec503158b8 (patch)
tree4b308e68145ff124c50c7a5d4ebec8f0060d35e6 /7_2/src
parent5d294755542190ac5135af8e120e313b55828625 (diff)
task7 initial commit
Diffstat (limited to '7_2/src')
-rw-r--r--7_2/src/drawable.c120
-rw-r--r--7_2/src/figure.c139
-rw-r--r--7_2/src/input.c116
3 files changed, 375 insertions, 0 deletions
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;
+}
+