#include "font.h" #include "display.h" #include "lvgl.h" #include "stdbool.h" #include static uint16_t find_glyph_id_in_cmap(const lv_font_fmt_txt_cmap_t * cmap, uint32_t character) { uint16_t cmap_last_character = cmap->range_start + cmap->range_length - 1; bool character_exists_in_cmap = character >= cmap->range_start && character <= cmap_last_character; if (character_exists_in_cmap) { uint16_t glyph_id = cmap->glyph_id_start - cmap->range_start + character; return glyph_id; } return 0; } bool lv_font_get_glyph_dsc_fmt_txt(const lv_font_t * font, lv_font_fmt_txt_glyph_dsc_t * dsc_out, uint32_t character) { lv_font_fmt_txt_dsc_t *font_dsc = (lv_font_fmt_txt_dsc_t *) font->dsc; for (uint16_t i = 0; i < font_dsc->cmap_num; i++) { uint16_t glyph_id = find_glyph_id_in_cmap(font_dsc->cmaps + i, character); if (glyph_id == 0) continue; *dsc_out = font_dsc->glyph_dsc[glyph_id]; return true; } return false; } // Left as a dummy definition for LVGL font compatibility. // We're not processing the bitmaps with draw buffers like LVGL does. const void * lv_font_get_bitmap_fmt_txt(lv_font_fmt_txt_glyph_dsc_t * g_dsc, lv_draw_buf_t * draw_buf) { } /** * @brief Draws a single character to the framebuffer using the specified font. * * This function renders a character glyph from an LVGL font to the framebuffer at the * specified location. The character is drawn in the provided color using a 1-bit bitmap * format where set bits are drawn as colored pixels and unset bits are left transparent. * * @param framebuffer Pointer to the framebuffer array where the character will be drawn. * Must be large enough to accommodate the character at the specified * location (typically DISPLAY_HEIGHT * DISPLAY_WIDTH pixels). * @param font Pointer to the LVGL font structure containing glyph data and metrics. * The font must be a valid LVGL formatted text font (lv_font_fmt_txt_dsc_t). * @param x_loc X coordinate (horizontal position) where the top-left of the character * bounding box will be drawn. Must be within framebuffer bounds. * @param y_loc Y coordinate (vertical position) where the top-left of the character * bounding box will be drawn. Must be within framebuffer bounds. * @param character The ASCII character code (0-255) to be drawn. * @param color The RGB565 color value to use when drawing the character pixels. * Pixels corresponding to set bits in the glyph bitmap will be drawn * in this color. * * @return The advance width of the drawn glyph in pixels (lower 16 bits of glyph_dsc.adv_w). * This value can be used to calculate the x position for the next character when * drawing text. Returns 0 if the character glyph was not found in the font. * * @note The function performs no bounds checking. Ensure x_loc and y_loc are within * the framebuffer dimensions to prevent buffer overruns. * @note The glyph bitmap is stored in a packed 1-bit format where each bit represents * one pixel (1 = draw pixel, 0 = skip pixel). * @note If the character is not found in the font's character map, the function returns * 0 without drawing anything. */ uint16_t draw_character(pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const char character, pixel_t color) { const lv_font_fmt_txt_dsc_t *font_dsc = (lv_font_fmt_txt_dsc_t *)font->dsc; lv_font_fmt_txt_glyph_dsc_t glyph_dsc; bool glyph_found = lv_font_get_glyph_dsc_fmt_txt(font, &glyph_dsc, character); if (!glyph_found) return 0; const uint16_t glyph_width = glyph_dsc.box_w; const uint16_t glyph_height = glyph_dsc.box_h; const int8_t glyph_ofs_x = glyph_dsc.ofs_x; const int8_t glyph_ofs_y = glyph_dsc.ofs_y; const uint32_t num_bitmap_bits = glyph_height * glyph_width; for (uint32_t bitmap_pixel_index = 0; bitmap_pixel_index < num_bitmap_bits; bitmap_pixel_index++) { const uint8_t current_bit_in_byte = bitmap_pixel_index % 8; const uint16_t bitmap_byte_index = glyph_dsc.bitmap_index + (bitmap_pixel_index / 8); const int32_t fb_pixel_x = x_loc + (bitmap_pixel_index % glyph_width) + glyph_ofs_x; const int32_t fb_pixel_y = y_loc + font->line_height - glyph_height + (bitmap_pixel_index / glyph_width) - glyph_ofs_y - font->base_line; const uint32_t fb_pixel_index = (fb_pixel_y * DISPLAY_WIDTH) + fb_pixel_x; const bool bit_on = font_dsc->glyph_bitmap[bitmap_byte_index] & (0x80 >> current_bit_in_byte); if (bit_on) { if (fb_pixel_x >= 0 && fb_pixel_x < DISPLAY_WIDTH && fb_pixel_y >= 0 && fb_pixel_y < DISPLAY_HEIGHT) { framebuffer[fb_pixel_index] = color; } } } return (glyph_dsc.adv_w & 0x0000FFFF); } /** * @brief Draws a null-terminated string to the framebuffer using the specified font. * * This function renders a complete string of characters to the framebuffer by iteratively * calling draw_character() for each character in the string. Characters are drawn horizontally * from left to right, with each character's advance width determining the spacing for the * next character. All characters are drawn on the same baseline (y_loc remains constant). * * @param framebuffer Pointer to the framebuffer array where the string will be drawn. * Must be large enough to accommodate the entire string at the specified * location (typically DISPLAY_HEIGHT * DISPLAY_WIDTH pixels). * @param font Pointer to the LVGL font structure containing glyph data and metrics. * The font must be a valid LVGL formatted text font (lv_font_fmt_txt_dsc_t). * @param x_loc X coordinate (horizontal position) where the first character's top-left * bounding box will be drawn. Must be within framebuffer bounds. * @param y_loc Y coordinate (vertical position) where all characters' top-left bounding * boxes will be drawn. Must be within framebuffer bounds. * @param string Pointer to a null-terminated C string (array of uint8_t) containing * the characters to be drawn. The function will stop drawing when it * encounters a null terminator ('\0'). * @param color The RGB565 color value to use when drawing all character pixels. * Pixels corresponding to set bits in each glyph bitmap will be drawn * in this color. * * @note The function performs no bounds checking. Ensure x_loc and y_loc are within * the framebuffer dimensions, and that the entire string will fit within the * framebuffer bounds to prevent buffer overruns. * @note Characters not found in the font (draw_character returns 0) will be skipped * without advancing the x position, which may cause subsequent characters to * overlap with missing characters. * @note The string must be null-terminated. The function will continue drawing until * it encounters a '\0' character. * @note All characters in the string are drawn on the same horizontal baseline (y_loc * remains constant for all characters). */ void draw_string(pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const char *string, pixel_t color) { uint32_t current_x = x_loc << 4; for (const char *char_ptr = string; *char_ptr != '\0'; char_ptr++) { uint16_t advance_width = draw_character(framebuffer, font, current_x >> 4, y_loc, *char_ptr, color); current_x += advance_width; } }