WIP: UI: Refactor blf_glyph for C++ Features #117794

Closed
Harley Acheson wants to merge 6 commits from Harley/blender:blf_glyph_cpp into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
5 changed files with 338 additions and 254 deletions

View File

@ -101,7 +101,7 @@ void BLF_cache_clear()
for (int i = 0; i < BLF_MAX_FONT; i++) {
FontBLF *font = global_font[i];
if (font) {
blf_glyph_cache_clear(font);
font->cache->clear();
}
}
}

View File

@ -420,7 +420,7 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(FontBLF *font,
/* Invalid unicode sequences return the byte value, stepping forward one.
* This allows `latin1` to display (which is sometimes used for file-paths). */
BLI_assert(charcode != BLI_UTF8_ERR);
GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
GlyphBLF *g = GlyphBLF::glyph_ensure(font, gc, charcode);
if (g && pen_x && !(font->flags & BLF_MONOSPACED)) {
*pen_x += blf_kerning(font, g_prev, g);
@ -433,7 +433,7 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(FontBLF *font,
#endif
#ifdef BLF_SUBPIXEL_AA
g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
g = g->glyph_refine(font, gc, *pen_x);
#endif
}
return g;
@ -469,7 +469,7 @@ static void blf_font_draw_ex(FontBLF *font,
continue;
}
/* Do not return this loop if clipped, we want every character tested. */
blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
g->draw(font, gc, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
pen_x += g->advance_x;
}
@ -482,9 +482,9 @@ static void blf_font_draw_ex(FontBLF *font,
}
void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
{
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
blf_font_draw_ex(font, gc, str, str_len, r_info, 0);
blf_glyph_cache_release(font);
font->cache->release();
}
int blf_font_draw_mono(
@ -497,7 +497,7 @@ int blf_font_draw_mono(
size_t i = 0;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
blf_batch_draw_begin(font);
@ -508,7 +508,7 @@ int blf_font_draw_mono(
continue;
}
/* Do not return this loop if clipped, we want every character tested. */
blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
g->draw(font, gc, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
const int col = UNLIKELY(g->c == '\t') ? (tab_columns - (columns % tab_columns)) :
BLI_wcwidth_safe(char32_t(g->c));
@ -518,7 +518,7 @@ int blf_font_draw_mono(
blf_batch_draw_end();
blf_glyph_cache_release(font);
font->cache->release();
return columns;
}
@ -674,9 +674,9 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
{
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
blf_font_draw_buffer_ex(font, gc, str, str_len, r_info, 0);
blf_glyph_cache_release(font);
font->cache->release();
}
/** \} */
@ -713,7 +713,7 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
#endif
#ifdef BLF_SUBPIXEL_AA
g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
g = g->glyph_refine(font, gc, *pen_x);
#endif
}
@ -731,7 +731,7 @@ size_t blf_font_width_to_strlen(
ft_pix width_new;
size_t i, i_prev;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
const int width_i = int(width);
for (i_prev = i = 0, width_new = pen_x = 0, g_prev = nullptr; (i < str_len) && str[i];
@ -747,7 +747,7 @@ size_t blf_font_width_to_strlen(
*r_width = ft_pix_to_int(width_new);
}
blf_glyph_cache_release(font);
font->cache->release();
return i_prev;
}
@ -759,7 +759,7 @@ size_t blf_font_width_to_rstrlen(
size_t i, i_prev, i_tmp;
const char *s, *s_prev;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
i = BLI_strnlen(str, str_len);
s = BLI_str_find_prev_char_utf8(&str[i], str);
@ -790,7 +790,7 @@ size_t blf_font_width_to_rstrlen(
*r_width = ft_pix_to_int(width_new);
}
blf_glyph_cache_release(font);
font->cache->release();
return i;
}
@ -867,9 +867,9 @@ static void blf_font_boundbox_ex(FontBLF *font,
void blf_font_boundbox(
FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
{
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0);
blf_glyph_cache_release(font);
font->cache->release();
}
void blf_font_width_and_height(FontBLF *font,
@ -945,9 +945,9 @@ float blf_font_height(FontBLF *font, const char *str, const size_t str_len, Resu
float blf_font_fixed_width(FontBLF *font)
{
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
float width = (gc) ? float(gc->fixed_width) : font->size / 2.0f;
blf_glyph_cache_release(font);
font->cache->release();
return width;
}
@ -966,7 +966,7 @@ void blf_font_boundbox_foreach_glyph(FontBLF *font,
ft_pix pen_x = 0;
size_t i = 0;
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
while ((i < str_len) && str[i]) {
const size_t i_curr = i;
@ -987,7 +987,7 @@ void blf_font_boundbox_foreach_glyph(FontBLF *font,
pen_x += g->advance_x;
}
blf_glyph_cache_release(font);
font->cache->release();
}
struct CursorPositionForeachGlyph_Data {
@ -1104,7 +1104,7 @@ static void blf_font_wrap_apply(FontBLF *font,
ft_pix line_height = blf_font_height_max_ft_pix(font);
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
GlyphCacheBLF *gc = font->cache->acquire();
struct WordWrapVars {
ft_pix wrap_width;
@ -1183,7 +1183,7 @@ static void blf_font_wrap_apply(FontBLF *font,
r_info->width = ft_pix_to_int(pen_x_next);
}
blf_glyph_cache_release(font);
font->cache->release();
}
/** Utility for #blf_font_draw__wrap. */
@ -1376,7 +1376,6 @@ static void blf_font_fill(FontBLF *font)
font->char_width = 1.0f;
font->char_spacing = 0.0f;
BLI_listbase_clear(&font->cache);
font->kerning_cache = nullptr;
#if BLF_BLUR_ENABLE
font->blur = 0;
@ -1738,6 +1737,8 @@ static FontBLF *blf_font_new_impl(const char *filepath,
{
FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
font->cache = new GlyphCacheListBLF(font);
font->mem_name = mem_name ? BLI_strdup(mem_name) : nullptr;
font->filepath = filepath ? BLI_strdup(filepath) : nullptr;
if (mem) {
@ -1756,8 +1757,6 @@ static FontBLF *blf_font_new_impl(const char *filepath,
font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib;
BLI_mutex_init(&font->glyph_cache_mutex);
/* If we have static details about this font file, we don't have to load the Face yet. */
bool face_needed = true;
@ -1826,7 +1825,7 @@ void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_
void blf_font_free(FontBLF *font)
{
blf_glyph_cache_clear(font);
delete font->cache;
if (font->kerning_cache) {
MEM_freeN(font->kerning_cache);
@ -1854,8 +1853,6 @@ void blf_font_free(FontBLF *font)
MEM_freeN(font->mem_name);
}
BLI_mutex_end(&font->glyph_cache_mutex);
MEM_freeN(font);
}

View File

@ -71,40 +71,115 @@ static float from_16dot16(FT_Fixed value)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Glyph Cache
/** \name Glyph Cache List
* \{ */
static GlyphCacheBLF *blf_glyph_cache_find(const FontBLF *font, const float size)
GlyphCacheListBLF::GlyphCacheListBLF(FontBLF *font) : list{}, font(font)
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first;
while (gc) {
if (gc->size == size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
(gc->italic == ((font->flags & BLF_ITALIC) != 0)) &&
(gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) &&
(gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing))
{
return gc;
BLI_mutex_init(&glyph_cache_mutex);
};
GlyphCacheListBLF ::~GlyphCacheListBLF()
{
clear();
BLI_mutex_end(&glyph_cache_mutex);
};
GlyphCacheBLF *GlyphCacheListBLF::acquire()
{
BLI_mutex_lock(&glyph_cache_mutex);
GlyphCacheBLF *gc = nullptr;
for (auto &entry : list) {
if (entry->matches(font)) {
gc = entry;
break;
}
gc = gc->next;
}
return nullptr;
if (!gc) {
gc = new GlyphCacheBLF();
gc->init(font);
list.push_back(gc);
}
return gc;
}
static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
void GlyphCacheListBLF::release()
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new");
BLI_mutex_unlock(&glyph_cache_mutex);
}
gc->next = nullptr;
gc->prev = nullptr;
gc->size = font->size;
gc->bold = ((font->flags & BLF_BOLD) != 0);
gc->italic = ((font->flags & BLF_ITALIC) != 0);
gc->char_weight = font->char_weight;
gc->char_slant = font->char_slant;
gc->char_width = font->char_width;
gc->char_spacing = font->char_spacing;
void GlyphCacheListBLF::clear()
{
BLI_mutex_lock(&glyph_cache_mutex);
for (auto &entry : list) {
delete entry;
}
list.clear();
BLI_mutex_unlock(&glyph_cache_mutex);
}
memset(gc->bucket, 0, sizeof(gc->bucket));
/** \} */
/* -------------------------------------------------------------------- */
/** \name Glyph Cache Entry
* \{ */
GlyphCacheBLF::GlyphCacheBLF()
: next(nullptr),
prev(nullptr),
size(11.0f),
char_weight(400),
char_slant(0.0f),
char_width(1.0f),
char_spacing(1.0f),
bold(false),
italic(false),
bucket{nullptr, nullptr},
fixed_width(6),
texture(nullptr),
bitmap_result(nullptr),
bitmap_len(0),
bitmap_len_landed(0),
bitmap_len_alloc(0)
{
}
GlyphCacheBLF::~GlyphCacheBLF()
{
for (uint i = 0; i < ARRAY_SIZE(bucket); i++) {
while (GlyphBLF *g = static_cast<GlyphBLF *>(BLI_pophead(&bucket[i]))) {
delete g;
}
}
if (texture) {
GPU_texture_free(texture);
}
if (bitmap_result) {
MEM_freeN(bitmap_result);
}
}
bool GlyphCacheBLF::matches(FontBLF *font) const
{
return (size == font->size && (bold == ((font->flags & BLF_BOLD) != 0)) &&
(italic == ((font->flags & BLF_ITALIC) != 0)) && (char_weight == font->char_weight) &&
(char_slant == font->char_slant) && (char_width == font->char_width) &&
(char_spacing == font->char_spacing));
}
void GlyphCacheBLF::init(FontBLF *font)
{
size = font->size;
char_weight = font->char_weight;
char_slant = font->char_slant;
char_width = font->char_width;
char_spacing = font->char_spacing;
bold = (font->flags & BLF_BOLD) != 0;
italic = ((font->flags & BLF_ITALIC) != 0);
blf_ensure_size(font);
@ -114,82 +189,63 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
FT_Fixed advance = 0;
FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance);
/* Use CSS 'ch unit' width, advance of zero character. */
gc->fixed_width = int(advance >> 16);
fixed_width = int(advance >> 16);
}
else {
/* Font does not have a face or does not contain "0" so use CSS fallback of 1/2 of em. */
gc->fixed_width = int((font->ft_size->metrics.height / 2) >> 6);
fixed_width = int((font->ft_size->metrics.height / 2) >> 6);
}
if (gc->fixed_width < 1) {
gc->fixed_width = 1;
if (fixed_width < 1) {
fixed_width = 1;
}
BLI_addhead(&font->cache, gc);
return gc;
}
GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font)
void GlyphCacheBLF::cache_glyph(GlyphBLF *glyph, uint charcode, uint8_t subpixel)
{
BLI_mutex_lock(&font->glyph_cache_mutex);
GlyphCacheBLF *gc = blf_glyph_cache_find(font, font->size);
if (!gc) {
gc = blf_glyph_cache_new(font);
}
return gc;
BLI_addhead(&(bucket[blf_hash(charcode << 6 | subpixel)]), glyph);
}
void blf_glyph_cache_release(FontBLF *font)
GlyphBLF *GlyphCacheBLF::find_glyph(uint charcode, uint8_t subpixel) const
{
BLI_mutex_unlock(&font->glyph_cache_mutex);
GlyphBLF *g = static_cast<GlyphBLF *>(bucket[blf_hash(charcode << 6 | subpixel)].first);
return GlyphBLF::cache_match(g, charcode, subpixel);
}
static void blf_glyph_cache_free(GlyphCacheBLF *gc)
/** \} */
/* -------------------------------------------------------------------- */
/** \name GlyphBLF
* \{ */
GlyphBLF::GlyphBLF()
: next(nullptr),
prev(nullptr),
c(0),
idx(0),
box_xmin(0),
box_xmax(INT_MAX),
box_ymin(0),
box_ymax(INT_MAX),
advance_x(0),
subpixel(0),
lsb_delta(0),
rsb_delta(0),
offset(0),
bitmap(nullptr),
dims{0, 0},
pitch(0),
depth(0),
render_mode(0),
pos{0, 0},
glyph_cache(nullptr)
{
for (uint i = 0; i < ARRAY_SIZE(gc->bucket); i++) {
while (GlyphBLF *g = static_cast<GlyphBLF *>(BLI_pophead(&gc->bucket[i]))) {
blf_glyph_free(g);
}
}
if (gc->texture) {
GPU_texture_free(gc->texture);
}
if (gc->bitmap_result) {
MEM_freeN(gc->bitmap_result);
}
MEM_freeN(gc);
}
void blf_glyph_cache_clear(FontBLF *font)
GlyphBLF::~GlyphBLF()
{
BLI_mutex_lock(&font->glyph_cache_mutex);
while (GlyphCacheBLF *gc = static_cast<GlyphCacheBLF *>(BLI_pophead(&font->cache))) {
blf_glyph_cache_free(gc);
if (bitmap) {
MEM_freeN(bitmap);
}
BLI_mutex_unlock(&font->glyph_cache_mutex);
}
/**
* Try to find a glyph in cache.
*
* \return nullptr if not found.
*/
static GlyphBLF *blf_glyph_cache_find_glyph(const GlyphCacheBLF *gc,
uint charcode,
uint8_t subpixel)
{
GlyphBLF *g = static_cast<GlyphBLF *>(gc->bucket[blf_hash(charcode << 6 | subpixel)].first);
while (g) {
if (g->c == charcode && g->subpixel == subpixel) {
return g;
}
g = g->next;
}
return nullptr;
}
#ifdef BLF_GAMMA_CORRECT_GLYPHS
@ -232,14 +288,11 @@ static uchar blf_glyph_gamma(uchar c)
/**
* Add a rendered glyph to a cache.
*/
static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font,
GlyphCacheBLF *gc,
FT_GlyphSlot glyph,
uint charcode,
FT_UInt glyph_index,
uint8_t subpixel)
GlyphBLF *GlyphBLF::create(
FontBLF *font, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index, uint8_t subpixel)
{
GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get");
GlyphBLF *g = new GlyphBLF();
g->c = charcode;
g->idx = glyph_index;
g->advance_x = (ft_pix)glyph->advance.x;
@ -291,7 +344,7 @@ static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font,
}
const int buffer_size = g->dims[0] * g->dims[1] * g->depth;
g->bitmap = static_cast<uchar *>(MEM_mallocN(size_t(buffer_size), "glyph bitmap"));
g->bitmap = static_cast<uchar *>(MEM_mallocN(size_t(buffer_size), __func__));
if (ELEM(glyph->bitmap.pixel_mode,
FT_PIXEL_MODE_GRAY,
@ -351,12 +404,20 @@ static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font,
memcpy(g->bitmap, glyph->bitmap.buffer, size_t(buffer_size));
}
}
BLI_addhead(&(gc->bucket[blf_hash(g->c << 6 | subpixel)]), g);
return g;
}
GlyphBLF *GlyphBLF::cache_match(GlyphBLF *glyph, uint charcode, uint8_t subpixel)
{
while (glyph) {
if (glyph->c == charcode && glyph->subpixel == subpixel) {
return glyph;
}
glyph = glyph->next;
}
return nullptr;
}
/** \} */
/* -------------------------------------------------------------------- */
@ -791,7 +852,7 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode
/**
* Load a glyph into the glyph slot of a font's face object.
*/
static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index, bool outline_only)
static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index, bool outline_only = false)
{
int load_flags;
@ -1202,7 +1263,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
uint charcode,
uint8_t subpixel,
int fixed_width,
bool outline_only)
bool outline_only = false)
{
Harley marked this conversation as resolved Outdated

Isn't this array initialized by FT_Get_Var_Design_Coordinates? If so, zero initializing it here seems redundant

Isn't this array initialized by `FT_Get_Var_Design_Coordinates`? If so, zero initializing it here seems redundant
if (glyph_font != settings_font) {
blf_font_size(glyph_font, settings_font->size);
@ -1231,7 +1292,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
/* Font variations need to be set before glyph loading. Even if new value is zero. */
if (glyph_font->variations) {
FT_Fixed coords[BLF_VARIATIONS_MAX];
FT_Fixed coords[BLF_VARIATIONS_MAX] = {0};
/* Load current design coordinates. */
FT_Get_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
/* Update design coordinates with new values. */
@ -1285,12 +1346,12 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
return nullptr;
}
static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
GlyphCacheBLF *gc,
const uint charcode,
uint8_t subpixel)
GlyphBLF *GlyphBLF::glyph_ensure(FontBLF *font,
GlyphCacheBLF *gc,
const uint charcode,
uint8_t subpixel)

It feels a bit for a class to return a pointer to itself or potentially create a new instance. Just that it's handling logic that isn't really "self contained". So maybe going with a free function would be clearer here too

It feels a bit for a class to return a pointer to itself or potentially create a new instance. Just that it's handling logic that isn't really "self contained". So maybe going with a free function would be clearer here too
{
GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode, subpixel);
GlyphBLF *g = gc->find_glyph(charcode, subpixel);
if (g) {
return g;
}
@ -1304,81 +1365,69 @@ static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font,
}
FT_GlyphSlot glyph = blf_glyph_render(
font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width, false);
font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width);
if (glyph) {
/* Save this glyph in the initial font's cache. */
g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index, subpixel);
g = GlyphBLF::create(font, glyph, charcode, glyph_index, subpixel);
gc->cache_glyph(g, charcode, subpixel);
}
return g;
}
GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode)
{
return blf_glyph_ensure_ex(font, gc, charcode, 0);
}
#ifdef BLF_SUBPIXEL_AA
GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x)
GlyphBLF *GlyphBLF::glyph_refine(FontBLF *font, GlyphCacheBLF *gc, int32_t pen_x)
{
if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
/* Not if we are in mono mode (aliased) or the feature is turned off. */
return g;
return this;
}
if (font->size > 35.0f || g->dims[0] == 0 || g->advance_x < 0) {
if (font->size > 35.0f || dims[0] == 0 || advance_x < 0) {
/* Single position for large sizes, spaces, and combining characters. */
return g;
return this;
}
/* Four sub-pixel positions up to 16 point, 2 until 35 points. */
const uint8_t subpixel = uint8_t(pen_x & ((font->size > 16.0f) ? 32L : 48L));
if (g->subpixel != subpixel) {
g = blf_glyph_ensure_ex(font, gc, g->c, subpixel);
if (subpixel != subpixel) {
return GlyphBLF::glyph_ensure(font, gc, c, subpixel);
}
return g;
return this;
}
#endif
void blf_glyph_free(GlyphBLF *g)
{
if (g->bitmap) {
MEM_freeN(g->bitmap);
}
MEM_freeN(g);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Glyph Bounds Calculation
* \{ */
static void blf_glyph_calc_rect(rcti *rect, GlyphBLF *g, const int x, const int y)
void GlyphBLF::calc_rect(rcti *rect, const int x, const int y) const
{
rect->xmin = x + g->pos[0];
rect->xmax = rect->xmin + g->dims[0];
rect->ymin = y + g->pos[1];
rect->ymax = rect->ymin - g->dims[1];
rect->xmin = x + pos[0];
rect->xmax = rect->xmin + dims[0];
rect->ymin = y + pos[1];
rect->ymax = rect->ymin - dims[1];
}
static void blf_glyph_calc_rect_test(rcti *rect, GlyphBLF *g, const int x, const int y)
void GlyphBLF::calc_rect_test(rcti *rect, const int x, const int y)
{
/* Intentionally check with `g->advance`, because this is the
* width used by BLF_width. This allows that the text slightly
* overlaps the clipping border to achieve better alignment. */
rect->xmin = x + abs(g->pos[0]) + 1;
rect->xmax = x + std::min(ft_pix_to_int(g->advance_x), g->dims[0]);
rect->xmin = x + abs(pos[0]) + 1;
rect->xmax = x + std::min(ft_pix_to_int(advance_x), dims[0]);
rect->ymin = y;
rect->ymax = rect->ymin - g->dims[1];
rect->ymax = rect->ymin - dims[1];
}
static void blf_glyph_calc_rect_shadow(
rcti *rect, GlyphBLF *g, const int x, const int y, FontBLF *font)
void GlyphBLF::calc_rect_shadow(rcti *rect, const int x, const int y, FontBLF *font) const
{
blf_glyph_calc_rect(rect, g, x + font->shadow_x, y + font->shadow_y);
calc_rect(rect, x + font->shadow_x, y + font->shadow_y);
}
/** \} */
@ -1387,13 +1436,12 @@ static void blf_glyph_calc_rect_shadow(
/** \name Glyph Drawing
* \{ */
static void blf_texture_draw(GlyphBLF *g,
const uchar color[4],
const int glyph_size[2],
const int x1,
const int y1,
const int x2,
const int y2)
void GlyphBLF::texture_draw(const uchar color[4],
const int glyph_size[2],
const int x1,
const int y1,
const int x2,
const int y2) const
{
/* Only one vertex per glyph, geometry shader expand it into a quad. */
/* TODO: Get rid of Geom Shader because it's not optimal AT ALL for the GPU. */
@ -1404,9 +1452,9 @@ static void blf_texture_draw(GlyphBLF *g,
float(y2 + g_batch.ofs[1]));
copy_v4_v4_uchar(static_cast<uchar *>(GPU_vertbuf_raw_step(&g_batch.col_step)), color);
copy_v2_v2_int(static_cast<int *>(GPU_vertbuf_raw_step(&g_batch.glyph_size_step)), glyph_size);
*((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = g->offset;
*((int *)GPU_vertbuf_raw_step(&g_batch.glyph_comp_len_step)) = g->depth;
*((int *)GPU_vertbuf_raw_step(&g_batch.glyph_mode_step)) = g->render_mode;
*((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = offset;
*((int *)GPU_vertbuf_raw_step(&g_batch.glyph_comp_len_step)) = depth;
*((int *)GPU_vertbuf_raw_step(&g_batch.glyph_mode_step)) = render_mode;
g_batch.glyph_len++;
/* Flush cache if it's full. */
@ -1415,42 +1463,42 @@ static void blf_texture_draw(GlyphBLF *g,
}
}
static void blf_texture5_draw(
GlyphBLF *g, const uchar color_in[4], const int x1, const int y1, const int x2, const int y2)
void GlyphBLF::texture5_draw(
const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const
{
int glyph_size_flag[2];
int glyph_size_flag[2] = {0};
/* flag the x and y component signs for 5x5 blurring */
glyph_size_flag[0] = -g->dims[0];
glyph_size_flag[1] = -g->dims[1];
glyph_size_flag[0] = -dims[0];
glyph_size_flag[1] = -dims[1];
blf_texture_draw(g, color_in, glyph_size_flag, x1, y1, x2, y2);
texture_draw(color_in, glyph_size_flag, x1, y1, x2, y2);
}
static void blf_texture3_draw(
GlyphBLF *g, const uchar color_in[4], const int x1, const int y1, const int x2, const int y2)
void GlyphBLF::texture3_draw(
const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const
{
int glyph_size_flag[2];
int glyph_size_flag[2] = {0};
/* flag the x component sign for 3x3 blurring */
glyph_size_flag[0] = -g->dims[0];
glyph_size_flag[1] = g->dims[1];
glyph_size_flag[0] = -dims[0];
glyph_size_flag[1] = dims[1];
blf_texture_draw(g, color_in, glyph_size_flag, x1, y1, x2, y2);
texture_draw(color_in, glyph_size_flag, x1, y1, x2, y2);
}
void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, const int y)
void GlyphBLF::draw(FontBLF *font, GlyphCacheBLF *gc, const int x, const int y)
{
if ((!g->dims[0]) || (!g->dims[1])) {
if ((!dims[0]) || (!dims[1])) {
return;
}
if (g->glyph_cache == nullptr) {
if (glyph_cache == nullptr) {
if (font->tex_size_max == -1) {
font->tex_size_max = GPU_max_texture_size();
}
g->offset = gc->bitmap_len;
offset = gc->bitmap_len;
int buff_size = g->dims[0] * g->dims[1] * g->depth;
int buff_size = dims[0] * dims[1] * depth;
int bitmap_len = gc->bitmap_len + buff_size;
if (bitmap_len > gc->bitmap_len_alloc) {
@ -1471,10 +1519,10 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x,
gc->bitmap_len_landed = 0;
}
memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, size_t(buff_size));
memcpy(&gc->bitmap_result[gc->bitmap_len], bitmap, size_t(buff_size));
gc->bitmap_len = bitmap_len;
g->glyph_cache = gc;
glyph_cache = gc;
}
if (font->flags & BLF_CLIPPING) {
@ -1490,57 +1538,52 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x,
}
rcti rect_test;
blf_glyph_calc_rect_test(&rect_test, g, int(float(x) * xa), int(float(y) * ya));
calc_rect_test(&rect_test, int(float(x) * xa), int(float(y) * ya));
BLI_rcti_translate(&rect_test, font->pos[0], font->pos[1]);
if (!BLI_rcti_inside_rcti(&font->clip_rec, &rect_test)) {
return;
}
}
if (g_batch.glyph_cache != g->glyph_cache) {
if (g_batch.glyph_cache != glyph_cache) {
blf_batch_draw();
g_batch.glyph_cache = g->glyph_cache;
g_batch.glyph_cache = glyph_cache;
}
if (font->flags & BLF_SHADOW) {
rcti rect_ofs;
blf_glyph_calc_rect_shadow(&rect_ofs, g, x, y, font);
calc_rect_shadow(&rect_ofs, x, y, font);
if (font->shadow == 0) {
blf_texture_draw(g,
font->shadow_color,
g->dims,
rect_ofs.xmin,
rect_ofs.ymin,
rect_ofs.xmax,
rect_ofs.ymax);
texture_draw(
font->shadow_color, dims, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
}
else if (font->shadow <= 4) {
blf_texture3_draw(
g, font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
texture3_draw(
font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
}
else {
blf_texture5_draw(
g, font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
texture5_draw(
font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax);
}
}
rcti rect;
blf_glyph_calc_rect(&rect, g, x, y);
calc_rect(&rect, x, y);
#if BLF_BLUR_ENABLE
switch (font->blur) {
case 3:
blf_texture3_draw(g, font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
texture3_draw(font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
case 5:
blf_texture5_draw(g, font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
texture5_draw(font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
break;
default:
blf_texture_draw(g, font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
texture_draw(font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
}
#else
blf_texture_draw(g, font->color, g->dims, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
texture_draw(font->color, dims, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
#endif
}

View File

@ -9,8 +9,8 @@
#pragma once
struct FontBLF;
struct GlyphBLF;
struct GlyphCacheBLF;
class GlyphBLF;
class GlyphCacheBLF;
struct ResultBLF;
struct rcti;
@ -166,22 +166,6 @@ void blf_str_offset_to_glyph_bounds(struct FontBLF *font,
void blf_font_free(struct FontBLF *font);
struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font);
void blf_glyph_cache_release(struct FontBLF *font);
void blf_glyph_cache_clear(struct FontBLF *font);
/**
* Create (or load from cache) a fully-rendered bitmap glyph.
*/
struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode);
#ifdef BLF_SUBPIXEL_AA
struct GlyphBLF *blf_glyph_ensure_subpixel(struct FontBLF *font,
struct GlyphCacheBLF *gc,
struct GlyphBLF *g,
int32_t pen_x);
#endif
/**
* Convert a character's outlines into curves.
*/
@ -190,10 +174,6 @@ float blf_character_to_curves(FontBLF *font,
struct ListBase *nurbsbase,
const float scale);
void blf_glyph_free(struct GlyphBLF *g);
void blf_glyph_draw(
struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, int x, int y);
#ifdef WIN32
/* `blf_font_win32_compat.cc` */

View File

@ -8,6 +8,8 @@
#pragma once
#include <vector>
#include "GPU_texture.h"
#include "GPU_vertex_buffer.h"
@ -93,7 +95,7 @@ typedef struct BatchBLF {
/* Previous call `modelmatrix`. */
float mat[4][4];
bool enabled, active, simple_shader;
struct GlyphCacheBLF *glyph_cache;
GlyphCacheBLF *glyph_cache;
} BatchBLF;
extern BatchBLF g_batch;
@ -106,9 +108,31 @@ typedef struct KerningCacheBLF {
int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE];
} KerningCacheBLF;
typedef struct GlyphCacheBLF {
struct GlyphCacheBLF *next;
struct GlyphCacheBLF *prev;
class GlyphCacheListBLF {
private:
/**
* List of glyph caches (#GlyphCacheBLF) for this font for size, DPI, bold, italic.
* Use font->cache->acquire() and font->cache->release() to access cache!
*/
std::vector<GlyphCacheBLF *> list;
FontBLF *font;
/** Mutex lock for glyph cache. */
ThreadMutex glyph_cache_mutex;
public:
GlyphCacheListBLF(FontBLF *font);
~GlyphCacheListBLF();
GlyphCacheBLF *acquire();
void release();
void clear();
};
class GlyphCacheBLF {
private:
GlyphCacheBLF *next;
GlyphCacheBLF *prev;
/** Font size. */
float size;
@ -121,12 +145,13 @@ typedef struct GlyphCacheBLF {
bool bold;
bool italic;
/** Column width when printing monospaced. */
int fixed_width;
/** The glyphs. */
ListBase bucket[257];
public:
/** Column width when printing monospaced. */
int fixed_width;
/** Texture array, to draw the glyphs. */
GPUTexture *texture;
char *bitmap_result;
@ -134,12 +159,21 @@ typedef struct GlyphCacheBLF {
int bitmap_len_landed;
int bitmap_len_alloc;
} GlyphCacheBLF;
GlyphCacheBLF();
~GlyphCacheBLF();
bool matches(FontBLF *font) const;
void init(FontBLF *font);
void cache_glyph(GlyphBLF *glyph, uint charcode, uint8_t subpixel);
GlyphBLF *find_glyph(uint charcode, uint8_t subpixel) const;
};
typedef struct GlyphBLF {
struct GlyphBLF *next;
struct GlyphBLF *prev;
class GlyphBLF {
private:
GlyphBLF *next;
GlyphBLF *prev;
GlyphCacheBLF *glyph_cache;
public:
/** The character, as UTF-32. */
unsigned int c;
@ -183,8 +217,41 @@ typedef struct GlyphBLF {
*/
int pos[2];
struct GlyphCacheBLF *glyph_cache;
} GlyphBLF;
void calc_rect(rcti *rect, const int x, const int y) const;
void calc_rect_test(rcti *rect, const int x, const int y);
void calc_rect_shadow(rcti *rect, const int x, const int y, FontBLF *font) const;
void texture_draw(const uchar color[4],
const int glyph_size[2],
const int x1,
const int y1,
const int x2,
const int y2) const;
void texture5_draw(
const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const;
void texture3_draw(
const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const;
static GlyphBLF *create(
FontBLF *font, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index, uint8_t subpixel);
public:
GlyphBLF();
~GlyphBLF();
static GlyphBLF *glyph_ensure(struct FontBLF *font,
GlyphCacheBLF *gc,
uint charcode,
uint8_t subpixel = 0);
#ifdef BLF_SUBPIXEL_AA
GlyphBLF *glyph_refine(struct FontBLF *font, GlyphCacheBLF *gc, int32_t pen_x);
#endif
void draw(FontBLF *font, GlyphCacheBLF *gc, const int x, const int y);
static GlyphBLF *cache_match(GlyphBLF *glyph, uint charcode, uint8_t subpixel);
};
typedef struct FontBufInfoBLF {
/** For draw to buffer, always set this to NULL after finish! */
@ -355,9 +422,9 @@ typedef struct FontBLF {
/**
* List of glyph caches (#GlyphCacheBLF) for this font for size, DPI, bold, italic.
* Use blf_glyph_cache_acquire(font) and blf_glyph_cache_release(font) to access cache!
* Use GlyphCacheBLF::cache_acquire(font) and GlyphCacheBLF::cache_release(font) to access cache!
*/
ListBase cache;
GlyphCacheListBLF *cache;
/** Cache of unscaled kerning values. Will be NULL if font does not have kerning. */
KerningCacheBLF *kerning_cache;
@ -379,7 +446,4 @@ typedef struct FontBLF {
/** Data for buffer usage (drawing into a texture buffer) */
FontBufInfoBLF buf_info;
/** Mutex lock for glyph cache. */
ThreadMutex glyph_cache_mutex;
} FontBLF;