diff options
author | justanothercatgirl <sotov2070@gmail.com> | 2024-10-17 17:38:07 +0300 |
---|---|---|
committer | justanothercatgirl <sotov2070@gmail.com> | 2024-10-17 17:38:07 +0300 |
commit | 82ec99f51b2b3b7a7b36b43b22df07ec503158b8 (patch) | |
tree | 4b308e68145ff124c50c7a5d4ebec8f0060d35e6 /7_2/src | |
parent | 5d294755542190ac5135af8e120e313b55828625 (diff) |
task7 initial commit
Diffstat (limited to '7_2/src')
-rw-r--r-- | 7_2/src/drawable.c | 120 | ||||
-rw-r--r-- | 7_2/src/figure.c | 139 | ||||
-rw-r--r-- | 7_2/src/input.c | 116 |
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; +} + |