Fonts work (mostly)
This commit is contained in:
148
Core/Src/graphics/font.c
Normal file
148
Core/Src/graphics/font.c
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "font.h"
|
||||
#include "display.h"
|
||||
#include "lvgl.h"
|
||||
#include "stdbool.h"
|
||||
#include <stdint.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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(rgb565_pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t character, rgb565_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 uint32_t fb_pixel_x = x_loc + (bitmap_pixel_index % glyph_width) + glyph_ofs_x;
|
||||
const uint32_t line_top = y_loc + font->base_line - glyph_height;
|
||||
const uint32_t fb_pixel_y = line_top + (bitmap_pixel_index / glyph_width) - glyph_ofs_y;
|
||||
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)
|
||||
{
|
||||
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(rgb565_pixel_t *framebuffer, const lv_font_t *font, const uint16_t x_loc, const uint16_t y_loc, const uint8_t *string, rgb565_pixel_t color)
|
||||
{
|
||||
uint32_t current_x = x_loc << 4;
|
||||
|
||||
for (const uint8_t *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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user