diff options
| author | Nathan Reiner <nathan@nathanreiner.xyz> | 2023-03-21 21:17:17 +0100 |
|---|---|---|
| committer | Nathan Reiner <nathan@nathanreiner.xyz> | 2023-03-21 21:17:17 +0100 |
| commit | c0a7c5ddcb9e0e98f6d981448e7c54fab6621327 (patch) | |
| tree | d0307493efe92924ad267f6a0c5efb0fc1e16bc3 /drw.c | |
first sketch
Diffstat (limited to 'drw.c')
| -rw-r--r-- | drw.c | 271 |
1 files changed, 271 insertions, 0 deletions
@@ -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; +} |