aboutsummaryrefslogtreecommitdiff
path: root/drw.c
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2023-03-20 15:21:21 +0100
committerNathan Reiner <nathan@nathanreiner.xyz>2023-03-20 15:21:21 +0100
commit05e97f8346521b50fbedcc2e7d0679e297d4d98b (patch)
tree6f0a909ffd1c5bcf5e1b95fa7ae61d721826e7db /drw.c
make first sketch of bar using freetype2 instead of cairo
Diffstat (limited to 'drw.c')
-rw-r--r--drw.c271
1 files changed, 271 insertions, 0 deletions
diff --git a/drw.c b/drw.c
new file mode 100644
index 0000000..f65f330
--- /dev/null
+++ b/drw.c
@@ -0,0 +1,271 @@
+#include <sys/mman.h>
+#include <unistd.h>
+#include <math.h>
+#include <grapheme.h>
+
+#include "drw.h"
+#include "util.h"
+
+/* static function declarations */
+static Color to_color(uint32_t color);
+static uint32_t to_uint32_t(Color color);
+static void draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t color);
+
+
+Color
+to_color(uint32_t color)
+{
+ return *(Color*)(&color);
+}
+
+
+uint32_t
+to_uint32_t(Color color)
+{
+ return *(uint32_t*)(&color);
+}
+
+
+Canvas*
+create_drw(struct wl_shm *shm, unsigned width, unsigned height)
+{
+ struct wl_shm_pool *pool;
+ Canvas *canvas;
+ int stride;
+ int fd;
+
+ canvas = malloc(sizeof(Canvas));
+ canvas->width = width;
+ canvas->height = height;
+
+ stride = width * sizeof(uint32_t);
+ canvas->size = stride * height;
+
+ fd = allocate_shm_file(canvas->size);
+ if (fd == -1) {
+ return NULL;
+ }
+
+ canvas->data = mmap(
+ NULL,
+ canvas->size,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ fd,
+ 0
+ );
+
+ if (canvas->data == MAP_FAILED) {
+ close(fd);
+ return NULL;
+ }
+
+ pool = wl_shm_create_pool(
+ shm,
+ fd,
+ canvas->size
+ );
+
+ canvas->buffer = wl_shm_pool_create_buffer(
+ pool,
+ 0,
+ width,
+ height,
+ stride,
+ WL_SHM_FORMAT_XRGB8888
+ );
+
+ wl_shm_pool_destroy(pool);
+ close(fd);
+
+ return canvas;
+}
+
+
+void
+free_drw(Canvas *canvas)
+{
+ munmap(canvas->data, canvas->size);
+ free(canvas);
+}
+
+
+void
+draw_point(Canvas *canvas, unsigned x, unsigned y, uint32_t color)
+{
+ if (!(x < canvas->width && y < canvas->height))
+ return;
+
+ canvas->data[x + canvas->width * y] = color;
+}
+
+
+void
+draw_rect(Canvas *canvas, unsigned x, unsigned y, unsigned width, unsigned height, uint32_t color) {
+ int py;
+ int px;
+
+ for (py = y; py < y + height; ++py) {
+ for (px = x; px < x + width; ++px) {
+ draw_point(canvas, px, py, color);
+ }
+ }
+}
+
+Font *
+create_font(const char *fontpath, unsigned size)
+{
+ FT_Error error;
+ Font * font;
+
+ font = malloc(sizeof(Font));
+
+ error = FT_Init_FreeType(&font->library);
+
+ if (error)
+ die("cannot init library");
+
+ error = FT_New_Face(font->library, fontpath, 0, &font->face);
+ if (error)
+ die("cannot open face");
+
+ error = FT_Set_Pixel_Sizes(font->face, 0, size);
+ if (error)
+ die("cannot set char size");
+
+ error = FT_Select_Charmap(font->face, ft_encoding_unicode);
+ if (error)
+ die("cannot set unicode");
+
+ return font;
+}
+
+void
+free_font(Font *font)
+{
+ FT_Done_Face(font->face);
+ FT_Done_FreeType(font->library);
+ free(font);
+}
+
+
+void
+draw_bitmap(Canvas *canvas, FT_Bitmap *bitmap, unsigned x, unsigned y, uint32_t color)
+{
+ FT_Int i, j, p, q;
+ double strength;
+ uint32_t pixel;
+
+ Color fg = to_color(color);
+ Color bg;
+ Color c;
+
+ c.a = fg.a;
+
+ i = x;
+ p = 0;
+
+ while (p < bitmap->width) {
+ j = y;
+ q = 0;
+
+ while (q < bitmap->rows) {
+ if (i < 0 || j < 0 || i >= canvas->width || j >= canvas->height) {
+ j++;
+ q++;
+ continue;
+ }
+
+ bg = to_color(canvas->data[i + j * canvas->width]);
+ strength = bitmap->buffer[p + q * bitmap->width];
+ strength /= 255;
+
+ c.r = (strength * fg.r) + ((1 - strength) * bg.r);
+ c.g = (strength * fg.g) + ((1 - strength) * bg.g);
+ c.b = (strength * fg.b) + ((1 - strength) * bg.b);
+
+ pixel = to_uint32_t(c);
+ draw_point(canvas, i, j, pixel);
+
+ j++;
+ q++;
+ }
+
+ i++;
+ p++;
+ }
+}
+
+
+unsigned
+draw_font(Canvas *canvas, Font *font, const char *text, unsigned x, unsigned y, uint32_t color)
+{
+ FT_GlyphSlot slot;
+ FT_Error error;
+ FT_UInt glyph_index;
+ FT_UInt previous = 0;
+ uint_least32_t charcode;
+ FT_Bool has_kerning = FT_HAS_KERNING(font->face);
+ FT_Vector delta;
+
+ slot = font->face->glyph;
+
+ for (; *text;) {
+ text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode);
+
+ glyph_index = FT_Get_Char_Index(font->face, charcode);
+
+ if (has_kerning && previous && glyph_index) {
+ FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
+ x += delta.x >> 6;
+ }
+
+ error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER);
+ if (error) {
+ fprintf(stderr, "warning: char not loaded, skipping...\n");
+ continue;
+ }
+
+ draw_bitmap(canvas, &slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, color);
+
+ x += slot->advance.x >> 6;
+ }
+
+ return x;
+}
+
+unsigned
+font_width(Font *font, const char *text)
+{
+ FT_GlyphSlot slot;
+ FT_Error error;
+ FT_UInt glyph_index;
+ FT_UInt previous = 0;
+ uint_least32_t charcode;
+ FT_Bool has_kerning = FT_HAS_KERNING(font->face);
+ FT_Vector delta;
+ unsigned x = 0;
+
+ slot = font->face->glyph;
+
+ for (; *text;) {
+ text += grapheme_decode_utf8(text, sizeof(uint_least32_t), &charcode);
+
+ glyph_index = FT_Get_Char_Index(font->face, charcode);
+
+ if (has_kerning && previous && glyph_index) {
+ FT_Get_Kerning(font->face, previous, glyph_index, FT_KERNING_DEFAULT, &delta);
+ x += delta.x >> 6;
+ }
+
+ error = FT_Load_Glyph(font->face, glyph_index, FT_LOAD_RENDER);
+ if (error) {
+ fprintf(stderr, "warning: char not loaded, skipping...\n");
+ continue;
+ }
+
+ x += slot->advance.x >> 6;
+ }
+
+ return x;
+}