From c3dff4d7286991888bd79484c19adccc6926afc1 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Sun, 26 Feb 2023 13:47:34 -0800 Subject: [PATCH] altos/draw: Add transforms to polygon code This lets the polygons remain constant but have them get scaled/translated when presented on the screen. Signed-off-by: Keith Packard --- src/draw/Makefile | 6 +-- src/draw/ao_copy.c | 4 +- src/draw/ao_draw.h | 79 ++++++++++++++++++++++++++------ src/draw/ao_draw_int.h | 2 +- src/draw/ao_line.c | 16 +++---- src/draw/ao_logo.c | 22 +++++---- src/draw/ao_pattern.c | 12 ++--- src/draw/ao_poly.c | 100 +++++++++++++++++++++++++++-------------- src/draw/ao_text.c | 15 ++++--- src/draw/draw-test.c | 50 ++++++++++++++++----- src/draw/make-logo | 12 +++-- 11 files changed, 223 insertions(+), 95 deletions(-) diff --git a/src/draw/Makefile b/src/draw/Makefile index 7eee1fe6..721fa157 100644 --- a/src/draw/Makefile +++ b/src/draw/Makefile @@ -73,8 +73,8 @@ $(FONT_SRCS): font-convert ao_font.h: $(FONT_SRCS) grep -h '^const struct ao_font' $(FONT_SRCS) | sed -e 's/^/extern /' -e 's/ =.*$$/;/' > $@ -ao_logo.h: make-logo Makefile - nickle make-logo ao_logo 48 0 10 > $@ +ao_logo.h: make-logo + nickle make-logo ao_logo > $@ SRCS=\ draw-test.c \ @@ -92,7 +92,7 @@ OBJS=$(SRCS:.c=.o) LIBS=-lXrender -lX11 -lm -CFLAGS=-O0 -g +CFLAGS=-O2 -g $(WARN_FLAGS) HEADERS=\ ao_draw.h \ diff --git a/src/draw/ao_copy.c b/src/draw/ao_copy.c index 0e822932..312d1d72 100644 --- a/src/draw/ao_copy.c +++ b/src/draw/ao_copy.c @@ -17,11 +17,11 @@ #define bound(val,max,other) do { \ if (val < 0) { \ - other -= val; \ + other += (typeof(other)) (-val); \ val = 0; \ } \ if (val > max) { \ - other -= (val - max); \ + other -= (typeof(other)) (val - max); \ val = max; \ } \ } while (0) diff --git a/src/draw/ao_draw.h b/src/draw/ao_draw.h index fbbc61c4..b4ca6eac 100644 --- a/src/draw/ao_draw.h +++ b/src/draw/ao_draw.h @@ -30,6 +30,57 @@ struct ao_coord { float x, y; }; +struct ao_transform { + float x_scale, x_off; + float y_scale, y_off; +}; + +static inline float ao_t_x(float x, float y, const struct ao_transform *t) +{ + (void) y; + return x * t->x_scale + t->x_off; +} + +static inline int16_t ao_t_xi(float x, float y, const struct ao_transform *t) +{ + return (int16_t) (ao_t_x(x, y, t) + 0.5f); +} + +static inline float ao_t_y(float x, float y, const struct ao_transform *t) +{ + (void) x; + return y * t->y_scale + t->y_off; +} + +static inline int16_t ao_t_yi(float x, float y, const struct ao_transform *t) +{ + return (int16_t) (ao_t_y(x, y, t) + 0.5f); +} + +static inline float ao_t_x_c(const struct ao_coord *c, + const struct ao_transform *t) +{ + return ao_t_x(c->x, c->y, t); +} + +static inline float ao_t_y_c(const struct ao_coord *c, + const struct ao_transform *t) +{ + return ao_t_y(c->x, c->y, t); +} + +static inline int16_t +ao_stride(int16_t width) +{ + return (int16_t) ((width + 31) >> 5); +} + +static inline int16_t +ao_stride_bytes(int16_t width) +{ + return (int16_t) ((width + 7) >> 3); +} + struct ao_pattern { uint8_t pattern[8]; }; @@ -46,9 +97,9 @@ struct ao_font { const uint8_t *bytes; const uint16_t *pos; const struct ao_glyph_metrics *metrics; - int max_width; - int max_height; - int ascent; + int16_t max_width; + int16_t max_height; + int16_t ascent; }; void @@ -92,11 +143,12 @@ ao_line(const struct ao_bitmap *dst, uint8_t rop); void -ao_poly(const struct ao_bitmap *dst, - const struct ao_coord *coords, - uint16_t ncoords, - uint32_t fill, - uint8_t rop); +ao_poly(const struct ao_bitmap *dst, + const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint32_t fill, + uint8_t rop); void ao_text(const struct ao_bitmap *dst, @@ -108,12 +160,13 @@ ao_text(const struct ao_bitmap *dst, uint8_t rop); void -ao_logo(const struct ao_bitmap *dst, - const struct ao_font *font, - uint32_t fill, - uint8_t rop); +ao_logo(const struct ao_bitmap *dst, + const struct ao_transform *transform, + const struct ao_font *font, + uint32_t fill, + uint8_t rop); -extern const struct ao_font FrutigerLT_Roman_50_font; +extern const struct ao_transform ao_identity; #define AO_SHIFT 5 #define AO_UNIT (1 << AO_SHIFT) diff --git a/src/draw/ao_draw_int.h b/src/draw/ao_draw_int.h index 433aa409..f353526d 100644 --- a/src/draw/ao_draw_int.h +++ b/src/draw/ao_draw_int.h @@ -76,7 +76,7 @@ ao_bits_mask(int16_t x, int16_t w) { r = ao_right_mask((x)+n); \ l = ao_left_mask(x); \ if (l) { \ - n -= AO_UNIT - ((x) & AO_MASK); \ + n -= (int16_t) (AO_UNIT - ((x) & AO_MASK)); \ if (n < 0) { \ n = 0; \ l &= r; \ diff --git a/src/draw/ao_line.c b/src/draw/ao_line.c index 318f101e..c6b49ee0 100644 --- a/src/draw/ao_line.c +++ b/src/draw/ao_line.c @@ -142,12 +142,12 @@ struct ao_cbox { /* -b <= a, so we need to make a bigger */ static int16_t div_ceil(int32_t a, int16_t b) { - return (a + b + b - 1) / b - 1; + return (int16_t) ((a + b + b - 1) / b - 1); } static int16_t div_floor_plus_one(int32_t a, int16_t b) { - return (a + b) / b; + return (int16_t) ((a + b) / b); } static int8_t @@ -202,10 +202,10 @@ ao_clip_line(struct ao_cc *c, struct ao_cbox *b) adjust_minor = adj_min; } - c->e += adjust_major * c->e1 + adjust_minor * c->e3; + c->e = (int16_t) (c->e + adjust_major * c->e1 + adjust_minor * c->e3); - c->major += c->sign_major * adjust_major; - c->minor += c->sign_minor * adjust_minor; + c->major = (int16_t) (c->major + c->sign_major * adjust_major); + c->minor = (int16_t) (c->minor + c->sign_minor * adjust_minor); return true; } @@ -239,7 +239,7 @@ ao_line(const struct ao_bitmap *dst, if (adx > ady) { axis = X_AXIS; e1 = ady << 1; - e2 = e1 - (adx << 1); + e2 = e1 - (int16_t) (adx << 1); e = e1 - adx; clip_1.major = x1; @@ -256,7 +256,7 @@ ao_line(const struct ao_bitmap *dst, } else { axis = Y_AXIS; e1 = adx << 1; - e2 = e1 - (ady << 1); + e2 = e1 - (int16_t) (ady << 1); e = e1 - ady; clip_1.major = y1; @@ -289,7 +289,7 @@ ao_line(const struct ao_bitmap *dst, if (!ao_clip_line(&clip_2, &cbox)) return; - len = clip_1.sign_major * (clip_2.major - clip_1.major) + clip_2.first; + len = (int16_t) (clip_1.sign_major * (clip_2.major - clip_1.major) + clip_2.first); if (len <= 0) return; diff --git a/src/draw/ao_logo.c b/src/draw/ao_logo.c index 1469ae21..d2d778ae 100644 --- a/src/draw/ao_logo.c +++ b/src/draw/ao_logo.c @@ -22,13 +22,19 @@ #define ARRAYSIZE(a) (sizeof(a) / sizeof((a)[0])) void -ao_logo(const struct ao_bitmap *dst, - const struct ao_font *font, - uint32_t fill, - uint8_t rop) +ao_logo(const struct ao_bitmap *dst, + const struct ao_transform *transform, + const struct ao_font *font, + uint32_t fill, + uint8_t rop) { - ao_poly(dst, ao_logo_top, ARRAYSIZE(ao_logo_top), 0x00000000, AO_COPY); - ao_poly(dst, ao_logo_bottom, ARRAYSIZE(ao_logo_bottom), 0x00000000, AO_COPY); - ao_text(dst, font, 38, 31, "Altus", 0x00000000, AO_COPY); - ao_text(dst, font, 38, 57, "Metrum", 0x00000000, AO_COPY); + if (!transform) + transform = &ao_identity; + int16_t name_x = ao_t_xi(ao_logo_width, 0.0f, transform); + int16_t name_y1 = ao_t_yi(ao_logo_width, 0.5f, transform); + int16_t name_y2 = ao_t_yi(ao_logo_width, 0.98f, transform); + ao_poly(dst, ao_logo_top, ARRAYSIZE(ao_logo_top), transform, fill, rop); + ao_poly(dst, ao_logo_bottom, ARRAYSIZE(ao_logo_bottom), transform, fill, rop); + ao_text(dst, font, name_x, name_y1, "Altus", fill, rop); + ao_text(dst, font, name_x, name_y2, "Metrum", fill, rop); } diff --git a/src/draw/ao_pattern.c b/src/draw/ao_pattern.c index 4d8c42c8..892fc49f 100644 --- a/src/draw/ao_pattern.c +++ b/src/draw/ao_pattern.c @@ -21,7 +21,7 @@ ao_pattern_expand(uint8_t v, uint8_t rot) uint32_t r; if (rot) - v = ao_left(v, 8-rot) | ao_right(v, rot); + v = (uint8_t) ao_left(v, 8-rot) | (uint8_t) ao_right(v, rot); r = v; return (r << 24) | (r << 16) | (r << 8) | (r); } @@ -53,17 +53,17 @@ ao_pattern(const struct ao_bitmap *dst, ao_clip(y2, 0, dst->height); if (x < x2 && y < y2) { - int xrot = (x - pat_x) & 7; - int yrot = (y - pat_y) & 7; - int i; + uint8_t xrot = (x - pat_x) & 7; + uint8_t yrot = (y - pat_y) & 7; + uint8_t i; int16_t dst_x, dst_y; for (i = 0; i < 8; i++) pat[(i + yrot) & 7] = ao_pattern_expand(pattern->pattern[i], xrot); for (dst_y = y; dst_y < y2; dst_y += 8) { - int h = min(y2 - dst_y, 8); + int16_t h = (int16_t) min(y2 - dst_y, 8); for (dst_x = x; dst_x < x2; dst_x += 8) { - int w = min(x2 - dst_x, 8); + int16_t w = (int16_t) min(x2 - dst_x, 8); ao_blt(pat, 1, 0, dst->base + dst_y * dst->stride, diff --git a/src/draw/ao_poly.c b/src/draw/ao_poly.c index 7fa351be..994f0a36 100644 --- a/src/draw/ao_poly.c +++ b/src/draw/ao_poly.c @@ -22,6 +22,33 @@ #include #include +const struct ao_transform ao_identity = { + .x_scale = 1.0f, .x_off = 0.0f, + .y_scale = 1.0f, .y_off = 0.0f +}; + +static float +_x(const struct ao_coord *coords, + const struct ao_transform *transform, + uint16_t coord) +{ + return ao_t_x_c(&coords[coord], transform); +} + +static float +_y(const struct ao_coord *coords, + const struct ao_transform *transform, + uint16_t coord) +{ + return ao_t_y_c(&coords[coord], transform); +} + +static uint16_t +_next(uint16_t ncoords, uint16_t edge) +{ + return edge == ncoords - 1 ? 0 : edge + 1; +} + /* * Return if the given edge is 'live' at the specified y coordinate. * That means the edge spans the y value. Horizontal lines are never @@ -30,12 +57,12 @@ static bool ao_edge_live(const struct ao_coord *coords, uint16_t ncoords, + const struct ao_transform *transform, uint16_t edge, float y) { - int next_edge = (edge == ncoords - 1) ? 0 : edge + 1; - float y1 = coords[edge].y; - float y2 = coords[next_edge].y; + float y1 = _y(coords, transform, edge); + float y2 = _y(coords, transform, _next(ncoords, edge)); if (y1 > y2) return y2 <= y && y < y1; @@ -47,21 +74,22 @@ ao_edge_live(const struct ao_coord *coords, * Compute the X coordinate for a given edge at a specified y value */ static int16_t -ao_edge_x(const struct ao_coord *coords, - uint16_t ncoords, - uint16_t edge, - float y) +ao_edge_x(const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint16_t edge, + float y) { - int next_edge = (edge == ncoords - 1) ? 0 : edge + 1; - float x1 = coords[edge].x; - float x2 = coords[next_edge].x; - float y1 = coords[edge].y; - float y2 = coords[next_edge].y; + uint16_t next_edge = _next(ncoords, edge); + float x1 = _x(coords, transform, edge); + float x2 = _x(coords, transform, next_edge); + float y1 = _y(coords, transform, edge); + float y2 = _y(coords, transform, next_edge); float dx = x2 - x1; float dy = y2 - y1; float off_y = y - y1; - return x1 + (off_y * dx) / dy; + return (int16_t) (x1 + (off_y * dx) / dy + 0.5f); } struct next_x { @@ -75,10 +103,11 @@ struct next_x { * if there are no more edges. */ static bool -ao_next_x(const struct ao_coord *coords, - uint16_t ncoords, - struct next_x *this_x, - float y) +ao_next_x(const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + struct next_x *this_x, + float y) { uint16_t edge; float next_x = FLT_MAX; @@ -86,8 +115,8 @@ ao_next_x(const struct ao_coord *coords, bool ret = false; for (edge = 0; edge < ncoords; edge++) { - if (ao_edge_live(coords, ncoords, edge, y)) { - float nx = ao_edge_x(coords, ncoords, edge, y); + if (ao_edge_live(coords, ncoords, transform, edge, y)) { + float nx = ao_edge_x(coords, ncoords, transform, edge, y); if (this_x->x < nx || (this_x->x == nx && this_x->edge < edge)) { if (nx < next_x) { next_x = nx; @@ -113,8 +142,8 @@ ao_span(const struct ao_bitmap *dst, uint32_t fill, uint8_t rop) { - int16_t ix1 = floorf(x1 + 0.5f); - int16_t ix2 = floorf(x2 + 0.5f); + int16_t ix1 = (int16_t) floorf(x1 + 0.5f); + int16_t ix2 = (int16_t) floorf(x2 + 0.5f); int16_t iy = (int16_t) y; ao_rect(dst, ix1, iy, ix2 - ix1, 1, fill, rop); } @@ -124,12 +153,13 @@ ao_span(const struct ao_bitmap *dst, * indication of whether the edge goes upwards or downwards */ static int -ao_wind(const struct ao_coord *coords, - uint16_t ncoords, - uint16_t edge) +ao_wind(const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint16_t edge) { - uint16_t next_edge = (edge == ncoords - 1) ? 0 : edge + 1; - return coords[edge].y > coords[next_edge].y ? 1 : -1; + uint16_t next_edge = _next(ncoords, edge); + return _y(coords, transform, edge) > _y(coords, transform, next_edge) ? 1 : -1; } /* @@ -137,9 +167,10 @@ ao_wind(const struct ao_coord *coords, */ void ao_poly(const struct ao_bitmap *dst, - const struct ao_coord *coords, - uint16_t ncoords, - uint32_t fill, + const struct ao_coord *coords, + uint16_t ncoords, + const struct ao_transform *transform, + uint32_t fill, uint8_t rop) { float y_min, y_max; @@ -149,12 +180,15 @@ ao_poly(const struct ao_bitmap *dst, struct next_x next_x; int wind; + if (!transform) + transform = &ao_identity; + /* * Find the y limits of the polygon */ - y_min = y_max = coords[0].y; + y_min = y_max = _y(coords, transform, 0); for (edge = 1; edge < ncoords; edge++) { - y = coords[edge].y; + y = _y(coords, transform, edge); if (y < y_min) y_min = y; else if (y > y_max) @@ -172,7 +206,7 @@ ao_poly(const struct ao_bitmap *dst, next_x.x = INT16_MIN; next_x.edge = 0; wind = 0; - while (ao_next_x(coords, ncoords, &next_x, y)) { + while (ao_next_x(coords, ncoords, transform, &next_x, y)) { /* * Fill the previous span if winding is @@ -182,7 +216,7 @@ ao_poly(const struct ao_bitmap *dst, ao_span(dst, x, next_x.x, y, fill, rop); /* Adjust winding for the current span */ - wind += ao_wind(coords, ncoords, next_x.edge); + wind += ao_wind(coords, ncoords, transform, next_x.edge); /* Step to next span start x value */ x = next_x.x; diff --git a/src/draw/ao_text.c b/src/draw/ao_text.c index be192388..cb1bc5ab 100644 --- a/src/draw/ao_text.c +++ b/src/draw/ao_text.c @@ -27,12 +27,12 @@ ao_text(const struct ao_bitmap *dst, uint32_t fill, uint8_t rop) { - int glyph_stride = (font->max_width + 31) / 32; + int16_t glyph_stride = ao_stride(font->max_width); uint32_t src[glyph_stride * font->max_height]; char c; int h; - int8_t x_off, y_off, advance; - int byte_width; + int16_t x_off = 0, y_off = 0, advance = 0; + int16_t byte_width = 0; struct ao_bitmap src_bitmap = { .base = src, @@ -45,11 +45,12 @@ ao_text(const struct ao_bitmap *dst, if (!font->metrics) { src_bitmap.width = font->max_width; - src_bitmap.height = font->max_width; + src_bitmap.height = font->max_height; src_bitmap.stride = glyph_stride; x_off = 0; y_off = font->ascent; advance = font->max_width; + byte_width = ao_stride_bytes(font->max_width); } while ((c = *string++)) { const uint8_t *bytes = &font->bytes[font->pos[(uint8_t) c]]; @@ -58,15 +59,15 @@ ao_text(const struct ao_bitmap *dst, const struct ao_glyph_metrics *m = &font->metrics[(uint8_t) c]; src_bitmap.width = m->width; src_bitmap.height = m->height; - src_bitmap.stride = (m->width + 31) / 32; + src_bitmap.stride = ao_stride(m->width); x_off = m->x_off; y_off = m->y_off; advance = m->advance; - byte_width = ((src_bitmap.width + 7) / 8); + byte_width = ao_stride_bytes(m->width); } for (h = 0; h < src_bitmap.height; h++) - memcpy(&src[h * src_bitmap.stride], &bytes[h * byte_width], byte_width); + memcpy(&src[h * src_bitmap.stride], &bytes[h * byte_width], (size_t) byte_width); ao_copy(dst, x + x_off, y - y_off, src_bitmap.width, src_bitmap.height, diff --git a/src/draw/draw-test.c b/src/draw/draw-test.c index 58e08a40..98976eea 100644 --- a/src/draw/draw-test.c +++ b/src/draw/draw-test.c @@ -39,10 +39,10 @@ static struct ao_bitmap fb = { #define BIG_FONT FrutigerLT_Roman_64_font #define SMALL_FONT FrutigerLT_Roman_12_font -#define LOGO_FONT FrutigerLT_Roman_24_font +#define LOGO_FONT BenguiatGothicStd_Bold_26_font #define VALUE_Y BIG_FONT.ascent -#define LABEL_Y BIG_FONT.ascent + SMALL_FONT.ascent + 2 +#define LABEL_Y (int16_t) (BIG_FONT.ascent + SMALL_FONT.ascent + 2) #define BOX_X 2 #define PAD_X 90 #define BOX_LABEL_X 30 @@ -51,7 +51,7 @@ static struct ao_bitmap fb = { static int box_number = 1; static int pad_number = 1; -static bool do_polys = false; +static int do_polys = 0; static const struct ao_coord trek[] = { { .x = 90, .y = 0 }, @@ -77,16 +77,39 @@ static const struct ao_coord donut[] = { #define NCOORD_DONUT (sizeof(donut)/sizeof(donut[0])) +static const struct ao_coord bowtie[] = { + { .x = 0, .y = 0 }, + { .x = 32, .y = 32 }, + { .x = 0, .y = 32 }, + { .x = 32, .y = 0 }, +}; + +#define NCOORD_BOWTIE (sizeof(bowtie)/sizeof(bowtie[0])) + +static const struct ao_transform logo_transform = { + .x_scale = 48, .x_off = 0, + .y_scale = 48, .y_off = 10, +}; + void HandleExpose(Display *dpy, Window win, GC gc) { + char str[64]; + ao_rect(&fb, 0, 0, WIDTH, HEIGHT, 0xffffffff, AO_COPY); - if (do_polys) { - ao_logo(&fb, &LOGO_FONT, 0x00000000, AO_COPY); -// ao_poly(&fb, trek, NCOORD_TREK, 0x00000000, AO_COPY); -// ao_poly(&fb, donut, NCOORD_DONUT, 0x00000000, AO_COPY); - } else { - char str[64]; + switch (do_polys) { + case 1: + ao_logo(&fb, &logo_transform, &LOGO_FONT, 0x00000000, AO_COPY); + break; + case 2: + ao_poly(&fb, trek, NCOORD_TREK, NULL, 0x00000000, AO_COPY); + ao_poly(&fb, donut, NCOORD_DONUT, NULL, 0x00000000, AO_COPY); + break; + case 3: + ao_poly(&fb, bowtie, NCOORD_BOWTIE, NULL, 0x00000000, AO_COPY); + break; + default: + case 0: sprintf(str, "%02d", box_number); ao_text(&fb, &BIG_FONT, BOX_X, VALUE_Y, str, 0x00000000, AO_COPY); @@ -97,6 +120,7 @@ void HandleExpose(Display *dpy, Window win, GC gc) ao_text(&fb, &SMALL_FONT, PAD_LABEL_X, LABEL_Y, "pad", 0x00000000, AO_COPY); ao_line(&fb, SEP_X, 0, SEP_X, HEIGHT, 0x00000000, AO_COPY); + break; } XImage *image = XCreateImage(dpy, visual, 1, XYBitmap, 0, (char *) bits, WIDTH, HEIGHT, 32, STRIDE*4); @@ -135,7 +159,9 @@ HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev) box_number = 99; break; case 's': - do_polys = !do_polys; + do_polys++; + if (do_polys == 4) + do_polys = 0; break; case 'c': break; @@ -147,4 +173,8 @@ HandleKeyPress(Display *dpy, Window win, GC gc, XEvent *ev) void HandleKeyRelease(Display *dpy, Window win, GC gc, XEvent *ev) { + (void) dpy; + (void) win; + (void) gc; + (void) ev; } diff --git a/src/draw/make-logo b/src/draw/make-logo index ede1c371..5e52cc87 100755 --- a/src/draw/make-logo +++ b/src/draw/make-logo @@ -94,9 +94,9 @@ print_poly(coord_t[] polygon, real height, bounds_t bounds, real x_pos, real y_p y = polygon[i].y; break; } - printf("\t{ .x = %8g, .y = %8g },\n", - (x - x_off) * scale + x_pos, - (y - y_off) * scale + y_pos); + printf("\t{ .x = %8.6ff, .y = %8.6ff },\n", + imprecise((x - x_off) * scale + x_pos), + imprecise((y - y_off) * scale + y_pos)); } } @@ -113,6 +113,10 @@ print_logo(string name, real height, real x_pos, real y_pos) printf("const struct ao_coord %s_bottom[] = {\n", name); print_poly(bottom, height, bounds, x_pos, y_pos); printf("};\n"); + printf("\n"); + real width = height * (bounds.max_x - bounds.min_x) / (bounds.max_y - bounds.min_y); + printf("static const float %s_height = %8.6ff;\n", name, height); + printf("static const float %s_width = %8.6ff;\n", name, width); } -print_logo(argv[1], string_to_real(argv[2]), string_to_real(argv[3]), string_to_real(argv[4])); +print_logo(argv[1], 1.0, 0, 0); -- 2.30.2