diff --git a/wayland/include/figure-draw.h b/wayland/include/figure-draw.h index a9aef1b..09fcffd 100644 --- a/wayland/include/figure-draw.h +++ b/wayland/include/figure-draw.h @@ -1,5 +1,5 @@ #ifndef FIGURE_DRAW_H -#define FIGURE_ANFIGURE_DRAW_HIMATE_H +#define FIGURE_DRAW_H #include "window.h" diff --git a/wayland/src/figure-draw.asm b/wayland/src/figure-draw.asm new file mode 100644 index 0000000..e69de29 diff --git a/wayland/src/figure-draw.c b/wayland/src/figure-draw.c new file mode 100644 index 0000000..0122258 --- /dev/null +++ b/wayland/src/figure-draw.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include "figure-draw.h" + +/* C implementation of the drawing routine. The .asm file simply forwards to this + * function so we keep the symbol present in an assembly file. */ +void figure_draw(struct window_draw_info* draw_info, float border_thickness, uint32_t border_color, uint32_t fill_color) +{ + if (!draw_info || !draw_info->data) + return; + + int w = draw_info->width; + int h = draw_info->height; + uint32_t *pixels = (uint32_t *)draw_info->data; + + struct figure_animation_info fig = draw_info->figure; + + /* center in pixels */ + float cx = fig.position.x * (float)w; + float cy = fig.position.y * (float)h; + float r = fig.radius * (float)w; /* normalized to width */ + float r2 = r * r; + float border = border_thickness; + if (border < 0.0f) border = 0.0f; + + /* bounding box */ + int minx = (int)floorf(cx - r); + int maxx = (int)ceilf(cx + r); + int miny = (int)floorf(cy - r); + int maxy = (int)ceilf(cy + r); + /* make sure we don't go out of bounds */ + if (miny < 0) miny = 0; + if (minx < 0) minx = 0; + if (maxy >= h) maxy = h - 1; + if (maxx >= w) maxx = w - 1; + + /* We'll compute pixel centers at (x + 0.5f, y + 0.5f) */ + for (int y = miny; y <= maxy; ++y) + { + float py = (float)y + 0.5f; + for (int x = minx; x <= maxx; ++x) + { + float px = (float)x + 0.5f; + int draw = 0; + int border_pixel = 0; + switch (fig.type) + { + case FIGURE_CIRCLE: + { + float dx = px - cx; + float dy = py - cy; + float d2 = dx*dx + dy*dy; + if (d2 <= r2) + { + draw = 1; + if (d2 >= (r - border)*(r - border)) + border_pixel = 1; + } + break; + } + case FIGURE_SQUARE: + { + float dx = fabsf(px - cx); + float dy = fabsf(py - cy); + if (dx <= r && dy <= r) + { + draw = 1; + if (fmaxf(dx, dy) >= r - border) + border_pixel = 1; + } + break; + } + case FIGURE_TRIANGLE: + { + /* Equilateral triangle centered at cx,cy. Apex up. * + * Vertices: A=(cx, cy - r), B=(cx + r*0.866, cy + r*0.5), C=(cx - r*0.866, cy + r*0.5) */ + float v1x = r * 0.8660254037844386f; + float v1y = r * 0.5f; + float ax = cx; float ay = cy - r; + float bx = cx + v1x; float by = cy + v1y; + float cx2 = cx - v1x; float cy2 = by; + + /* barycentric tests: point inside triangle if all cross products have same sign */ + float s1 = (px - bx)*(ay - by) - (ax - bx)*(py - by); + float s2 = (px - cx2)*(by - cy2) - (bx - cx2)*(py - cy2); + float s3 = (px - ax)*(cy2 - ay) - (cx2 - ax)*(py - ay); + int neg = (s1 < 0) + (s2 < 0) + (s3 < 0); + int pos = (s1 > 0) + (s2 > 0) + (s3 > 0); + if (neg == 0 || pos == 0) + { + draw = 1; + } + break; + } + default: + break; + } + + if (draw) + { + uint32_t col = border_pixel ? border_color : fill_color; + pixels[y * w + x] = col; + } + } + } +} + +/* C symbol exported to be called by minimal assembly wrapper */ diff --git a/wayland/src/window.c b/wayland/src/window.c index 5d2d604..8fc9b9f 100644 --- a/wayland/src/window.c +++ b/wayland/src/window.c @@ -1,5 +1,6 @@ #include "window.h" #include "registry.h" +#include "figure-draw.h" #include "xdg-shell-client-protocol.h" #include #include @@ -128,9 +129,12 @@ static void draw(struct wayland_window *win) { uint32_t *row = (uint32_t *)(bytes + y * stride); for (int32_t x = 0; x < (int32_t)draw_info->width; ++x) - row[x] = color; + row[x] = 0xFF000000; /* background black */ } + /* Draw figure into buffer. border thickness in pixels = 3.0f */ + figure_draw(&win->draw_info, 3.0f, 0xFFFFFFFF, color); + wl_surface_attach(win->wl_surface, win->buffer, 0, 0); wl_surface_damage_buffer(win->wl_surface, 0, 0, draw_info->width, draw_info->height); wl_surface_commit(win->wl_surface);