/* draw.c - software rendering onto an ARGB8888 mb_buffer. */ #include "draw.h" #include "font.h" #include /* wl_shm ARGB8888 and Win32 layered windows both hold premultiplied alpha. */ static uint32_t premul(uint32_t argb) { uint32_t a = argb >> 24; uint32_t r = (argb >> 16) & 0xff; uint32_t g = (argb >> 8) & 0xff; uint32_t b = argb & 0xff; r = r * a / 255; g = g * a / 255; b = b * a / 255; return (a << 24) | (r << 16) | (g << 8) | b; } /* Fill a logical rectangle, expanding each logical pixel to a scale*scale block * of device pixels. Clipping is in logical space; scale=1 is the identity. */ static void fill_premul(struct mb_buffer *b, int x, int y, int w, int h, uint32_t pm) { int s = b->scale; int x1 = x + w, y1 = y + h; if (x < 0) x = 0; if (y < 0) y = 0; if (x1 > b->w) x1 = b->w; if (y1 > b->h) y1 = b->h; int n = (x1 - x) * s; for (int row = y; row < y1; row++) { for (int sy = 0; sy < s; sy++) { uint32_t *p = b->px + (size_t)(row * s + sy) * b->stride + (size_t)x * s; for (int i = 0; i < n; i++) p[i] = pm; } } } void draw_fill(struct mb_buffer *b, int x, int y, int w, int h, uint32_t argb) { fill_premul(b, x, y, w, h, premul(argb)); } void draw_hline(struct mb_buffer *b, int x, int y, int len, int thick, uint32_t argb) { fill_premul(b, x, y, len, thick, premul(argb)); } void draw_vline(struct mb_buffer *b, int x, int y, int len, int thick, uint32_t argb) { fill_premul(b, x, y, thick, len, premul(argb)); } void draw_rect(struct mb_buffer *b, int x, int y, int w, int h, int thick, uint32_t argb) { uint32_t pm = premul(argb); fill_premul(b, x, y, w, thick, pm); /* top */ fill_premul(b, x, y + h - thick, w, thick, pm); /* bottom */ fill_premul(b, x, y, thick, h, pm); /* left */ fill_premul(b, x + w - thick, y, thick, h, pm); /* right */ } int text_height(int scale) { return FONT_H * scale; } int text_width(const char *s, int scale) { int n = 0; while (s[n]) n++; if (n == 0) return 0; return n * (FONT_W * scale) + (n - 1) * scale; /* scale-px gaps */ } int draw_text(struct mb_buffer *b, int x, int y, const char *s, int scale, uint32_t fg) { int advance = FONT_W * scale + scale; int w = text_width(s, scale); uint32_t fpm = premul(fg); int pen = x; for (const char *c = s; *c; c++) { const unsigned char *g = font_glyph(*c); for (int gy = 0; gy < FONT_H; gy++) { unsigned char bits = g[gy]; for (int gx = 0; gx < FONT_W; gx++) { if (!(bits & (1u << gx))) continue; fill_premul(b, pen + gx * scale, y + gy * scale, scale, scale, fpm); } } pen += advance; } return w; }