Files
test/source/blender/blenfont/intern/blf.cc
Aras Pranckevicius 3582e52f9c UI: Improved overlay text contrast with new outline text decoration
Overlay texts were previously drawn with two sets of shadows:
- 3px blur,
- 5px blur, slightly offset

But since the shadow color was always set to black, it was still
causing legibility issues when the text itself was dark (set
via theme for example).

This PR adds a new "outline" BLF text decoration, and uses that
for the overlays. And it picks text/outline color depending
on the "background" color of the view.

Details:

- Instead of "shadow level" integer where the only valid options
  are 0, 3 or 5, have a FontShadowType enum.
- Add a new FontShadowType::Outline enum entry, that does a 1px
  outline by doing a 3x3 dilation in the font shader.
- BLF_draw_default_shadowed is changed to do outline, instead of
  drawing the shadow twice.
- In the font shader, instead of encoding shadow type in signs of
  the glyph_size, pass that as a "flags" vertex attribute. Put
  font texture channel count into the same flags, so that the
  vertex size stays the same.
- Well actually, vertex size becomes smaller by 4 bytes, since turns
  out glyph_mode vertex attribute was not used for anything at all.

Images in the PR.

Co-authored-by: Harley Acheson <harley.acheson@gmail.com>
Pull Request: https://projects.blender.org/blender/blender/pulls/121383
2024-05-10 21:06:44 +02:00

1017 lines
21 KiB
C++

/* SPDX-FileCopyrightText: 2009 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup blf
*
* Main BlenFont (BLF) API, public functions for font handling.
*
* Wraps GPU display and FreeType.
*/
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
#include "MEM_guardedalloc.h"
#include "BLI_fileops.h"
#include "BLI_math_rotation.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_threads.h"
#include "BLF_api.hh"
#include "IMB_colormanagement.hh"
#include "GPU_matrix.hh"
#include "GPU_shader.hh"
#include "blf_internal.hh"
#include "blf_internal_types.hh"
#define BLF_RESULT_CHECK_INIT(r_info) \
if (r_info) { \
memset(r_info, 0, sizeof(*(r_info))); \
} \
((void)0)
FontBLF *global_font[BLF_MAX_FONT] = {nullptr};
/* XXX: should these be made into global_font_'s too? */
int blf_mono_font = -1;
int blf_mono_font_render = -1;
static FontBLF *blf_get(int fontid)
{
if (fontid >= 0 && fontid < BLF_MAX_FONT) {
return global_font[fontid];
}
return nullptr;
}
int BLF_init()
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
global_font[i] = nullptr;
}
return blf_font_init();
}
void BLF_exit()
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
FontBLF *font = global_font[i];
if (font) {
blf_font_free(font);
global_font[i] = nullptr;
}
}
blf_font_exit();
}
void BLF_reset_fonts()
{
const int def_font = BLF_default();
for (int i = 0; i < BLF_MAX_FONT; i++) {
FontBLF *font = global_font[i];
if (font && !ELEM(i, def_font, blf_mono_font, blf_mono_font_render) &&
!(font->flags & BLF_DEFAULT))
{
/* Remove fonts that are not used in the UI or part of the stack. */
blf_font_free(font);
global_font[i] = nullptr;
}
}
}
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);
}
}
}
bool blf_font_id_is_valid(int fontid)
{
return blf_get(fontid) != nullptr;
}
static int blf_search_by_mem_name(const char *mem_name)
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
const FontBLF *font = global_font[i];
if ((font == nullptr) || (font->mem_name == nullptr)) {
continue;
}
if (STREQ(font->mem_name, mem_name)) {
return i;
}
}
return -1;
}
static int blf_search_by_filepath(const char *filepath)
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
const FontBLF *font = global_font[i];
if ((font == nullptr) || (font->filepath == nullptr)) {
continue;
}
if (BLI_path_cmp(font->filepath, filepath) == 0) {
return i;
}
}
return -1;
}
static int blf_search_available()
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
if (!global_font[i]) {
return i;
}
}
return -1;
}
bool BLF_has_glyph(int fontid, uint unicode)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_get_char_index(font, unicode) != FT_Err_Ok;
}
return false;
}
bool BLF_is_loaded(const char *filepath)
{
return blf_search_by_filepath(filepath) >= 0;
}
bool BLF_is_loaded_mem(const char *name)
{
return blf_search_by_mem_name(name) >= 0;
}
int BLF_load(const char *filepath)
{
/* check if we already load this font. */
int i = blf_search_by_filepath(filepath);
if (i >= 0) {
FontBLF *font = global_font[i];
font->reference_count++;
return i;
}
return BLF_load_unique(filepath);
}
int BLF_load_unique(const char *filepath)
{
/* Don't search in the cache!! make a new
* object font, this is for keep fonts threads safe.
*/
int i = blf_search_available();
if (i == -1) {
printf("Too many fonts!!!\n");
return -1;
}
/* This isn't essential, it will just cause confusing behavior to load a font
* that appears to succeed, then doesn't show up. */
if (!BLI_exists(filepath)) {
printf("Can't find font: %s\n", filepath);
return -1;
}
FontBLF *font = blf_font_new_from_filepath(filepath);
if (!font) {
printf("Can't load font: %s\n", filepath);
return -1;
}
font->reference_count = 1;
global_font[i] = font;
return i;
}
void BLF_metrics_attach(const int fontid, const uchar *mem, const int mem_size)
{
FontBLF *font = blf_get(fontid);
if (font) {
blf_font_attach_from_mem(font, mem, mem_size);
}
}
int BLF_load_mem(const char *name, const uchar *mem, int mem_size)
{
int i = blf_search_by_mem_name(name);
if (i >= 0) {
// font = global_font[i]; /* UNUSED */
return i;
}
return BLF_load_mem_unique(name, mem, mem_size);
}
int BLF_load_mem_unique(const char *name, const uchar *mem, int mem_size)
{
/*
* Don't search in the cache, make a new object font!
* this is to keep the font thread safe.
*/
int i = blf_search_available();
if (i == -1) {
printf("Too many fonts!!!\n");
return -1;
}
if (!mem_size) {
printf("Can't load font: %s from memory!!\n", name);
return -1;
}
FontBLF *font = blf_font_new_from_mem(name, mem, mem_size);
if (!font) {
printf("Can't load font: %s from memory!!\n", name);
return -1;
}
font->reference_count = 1;
global_font[i] = font;
return i;
}
void BLF_unload(const char *filepath)
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
FontBLF *font = global_font[i];
if (font == nullptr || font->filepath == nullptr) {
continue;
}
if (BLI_path_cmp(font->filepath, filepath) == 0) {
BLI_assert(font->reference_count > 0);
font->reference_count--;
if (font->reference_count == 0) {
blf_font_free(font);
global_font[i] = nullptr;
}
}
}
}
void BLF_unload_id(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
BLI_assert(font->reference_count > 0);
font->reference_count--;
if (font->reference_count == 0) {
blf_font_free(font);
global_font[fontid] = nullptr;
}
}
}
void BLF_unload_all()
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
FontBLF *font = global_font[i];
if (font) {
blf_font_free(font);
global_font[i] = nullptr;
}
}
blf_mono_font = -1;
blf_mono_font_render = -1;
BLF_default_set(-1);
}
void BLF_enable(int fontid, int option)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->flags |= option;
}
}
void BLF_disable(int fontid, int option)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->flags &= ~option;
}
}
void BLF_character_weight(int fontid, int weight)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->char_weight = weight;
}
}
void BLF_aspect(int fontid, float x, float y, float z)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->aspect[0] = x;
font->aspect[1] = y;
font->aspect[2] = z;
}
}
void BLF_position(int fontid, float x, float y, float z)
{
FontBLF *font = blf_get(fontid);
if (font) {
float xa, ya, za;
float remainder;
if (font->flags & BLF_ASPECT) {
xa = font->aspect[0];
ya = font->aspect[1];
za = font->aspect[2];
}
else {
xa = 1.0f;
ya = 1.0f;
za = 1.0f;
}
remainder = x - floorf(x);
if (remainder > 0.4f && remainder < 0.6f) {
if (remainder < 0.5f) {
x -= 0.1f * xa;
}
else {
x += 0.1f * xa;
}
}
remainder = y - floorf(y);
if (remainder > 0.4f && remainder < 0.6f) {
if (remainder < 0.5f) {
y -= 0.1f * ya;
}
else {
y += 0.1f * ya;
}
}
remainder = z - floorf(z);
if (remainder > 0.4f && remainder < 0.6f) {
if (remainder < 0.5f) {
z -= 0.1f * za;
}
else {
z += 0.1f * za;
}
}
font->pos[0] = round_fl_to_int(x);
font->pos[1] = round_fl_to_int(y);
font->pos[2] = round_fl_to_int(z);
}
}
void BLF_size(int fontid, float size)
{
FontBLF *font = blf_get(fontid);
if (font) {
blf_font_size(font, size);
}
}
void BLF_color4ubv(int fontid, const uchar rgba[4])
{
FontBLF *font = blf_get(fontid);
if (font) {
font->color[0] = rgba[0];
font->color[1] = rgba[1];
font->color[2] = rgba[2];
font->color[3] = rgba[3];
}
}
void BLF_color3ubv_alpha(int fontid, const uchar rgb[3], uchar alpha)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->color[0] = rgb[0];
font->color[1] = rgb[1];
font->color[2] = rgb[2];
font->color[3] = alpha;
}
}
void BLF_color3ubv(int fontid, const uchar rgb[3])
{
BLF_color3ubv_alpha(fontid, rgb, 255);
}
void BLF_color4ub(int fontid, uchar r, uchar g, uchar b, uchar alpha)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->color[0] = r;
font->color[1] = g;
font->color[2] = b;
font->color[3] = alpha;
}
}
void BLF_color3ub(int fontid, uchar r, uchar g, uchar b)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->color[0] = r;
font->color[1] = g;
font->color[2] = b;
font->color[3] = 255;
}
}
void BLF_color4fv(int fontid, const float rgba[4])
{
FontBLF *font = blf_get(fontid);
if (font) {
rgba_float_to_uchar(font->color, rgba);
}
}
void BLF_color4f(int fontid, float r, float g, float b, float a)
{
const float rgba[4] = {r, g, b, a};
BLF_color4fv(fontid, rgba);
}
void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha)
{
float rgba[4];
copy_v3_v3(rgba, rgb);
rgba[3] = alpha;
BLF_color4fv(fontid, rgba);
}
void BLF_color3f(int fontid, float r, float g, float b)
{
const float rgba[4] = {r, g, b, 1.0f};
BLF_color4fv(fontid, rgba);
}
void BLF_batch_draw_begin()
{
BLI_assert(g_batch.enabled == false);
g_batch.enabled = true;
}
void BLF_batch_draw_flush()
{
if (g_batch.enabled) {
blf_batch_draw();
}
}
void BLF_batch_draw_end()
{
BLI_assert(g_batch.enabled == true);
blf_batch_draw(); /* Draw remaining glyphs */
g_batch.enabled = false;
}
static void blf_draw_gpu__start(const FontBLF *font)
{
/*
* The pixmap alignment hack is handle
* in BLF_position (old ui_rasterpos_safe).
*/
if ((font->flags & (BLF_ROTATION | BLF_ASPECT)) == 0) {
return; /* glyphs will be translated individually and batched. */
}
GPU_matrix_push();
GPU_matrix_translate_3f(font->pos[0], font->pos[1], font->pos[2]);
if (font->flags & BLF_ASPECT) {
GPU_matrix_scale_3fv(font->aspect);
}
if (font->flags & BLF_ROTATION) {
GPU_matrix_rotate_2d(RAD2DEG(font->angle));
}
}
static void blf_draw_gpu__end(const FontBLF *font)
{
if ((font->flags & (BLF_ROTATION | BLF_ASPECT)) != 0) {
GPU_matrix_pop();
}
}
void BLF_draw(int fontid, const char *str, const size_t str_len, ResultBLF *r_info)
{
BLF_RESULT_CHECK_INIT(r_info);
if (str_len == 0 || str[0] == '\0') {
return;
}
FontBLF *font = blf_get(fontid);
if (font) {
/* Avoid bgl usage to corrupt BLF drawing. */
GPU_bgl_end();
blf_draw_gpu__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw__wrap(font, str, str_len, r_info);
}
else {
blf_font_draw(font, str, str_len, r_info);
}
blf_draw_gpu__end(font);
}
}
int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth, int tab_columns)
{
if (str_len == 0 || str[0] == '\0') {
return 0;
}
FontBLF *font = blf_get(fontid);
int columns = 0;
if (font) {
blf_draw_gpu__start(font);
columns = blf_font_draw_mono(font, str, str_len, cwidth, tab_columns);
blf_draw_gpu__end(font);
}
return columns;
}
void BLF_boundbox_foreach_glyph(
int fontid, const char *str, size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data)
{
FontBLF *font = blf_get(fontid);
if (font) {
if (font->flags & BLF_WORD_WRAP) {
/* TODO: word-wrap support. */
BLI_assert(0);
}
else {
blf_font_boundbox_foreach_glyph(font, str, str_len, user_fn, user_data);
}
}
}
size_t BLF_str_offset_from_cursor_position(int fontid,
const char *str,
size_t str_len,
int location_x)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_str_offset_from_cursor_position(font, str, str_len, location_x);
}
return 0;
}
bool BLF_str_offset_to_glyph_bounds(int fontid,
const char *str,
size_t str_offset,
rcti *glyph_bounds)
{
FontBLF *font = blf_get(fontid);
if (font) {
blf_str_offset_to_glyph_bounds(font, str, str_offset, glyph_bounds);
return true;
}
return false;
}
int BLF_str_offset_to_cursor(
int fontid, const char *str, size_t str_len, size_t str_offset, float cursor_width)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_str_offset_to_cursor(font, str, str_len, str_offset, cursor_width);
}
return 0;
}
size_t BLF_width_to_strlen(
int fontid, const char *str, const size_t str_len, float width, float *r_width)
{
FontBLF *font = blf_get(fontid);
if (font) {
const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
size_t ret;
int width_result;
ret = blf_font_width_to_strlen(font, str, str_len, width / xa, &width_result);
if (r_width) {
*r_width = float(width_result) * xa;
}
return ret;
}
if (r_width) {
*r_width = 0.0f;
}
return 0;
}
size_t BLF_width_to_rstrlen(
int fontid, const char *str, const size_t str_len, float width, float *r_width)
{
FontBLF *font = blf_get(fontid);
if (font) {
const float xa = (font->flags & BLF_ASPECT) ? font->aspect[0] : 1.0f;
size_t ret;
int width_result;
ret = blf_font_width_to_rstrlen(font, str, str_len, width / xa, &width_result);
if (r_width) {
*r_width = float(width_result) * xa;
}
return ret;
}
if (r_width) {
*r_width = 0.0f;
}
return 0;
}
void BLF_boundbox(
int fontid, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
BLF_RESULT_CHECK_INIT(r_info);
if (font) {
if (font->flags & BLF_WORD_WRAP) {
blf_font_boundbox__wrap(font, str, str_len, r_box, r_info);
}
else {
blf_font_boundbox(font, str, str_len, r_box, r_info);
}
}
}
void BLF_width_and_height(
int fontid, const char *str, const size_t str_len, float *r_width, float *r_height)
{
FontBLF *font = blf_get(fontid);
if (font) {
blf_font_width_and_height(font, str, str_len, r_width, r_height, nullptr);
}
else {
*r_width = *r_height = 0.0f;
}
}
float BLF_width(int fontid, const char *str, const size_t str_len, ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
BLF_RESULT_CHECK_INIT(r_info);
if (font) {
return blf_font_width(font, str, str_len, r_info);
}
return 0.0f;
}
float BLF_fixed_width(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_font_fixed_width(font);
}
return 0.0f;
}
float BLF_height(int fontid, const char *str, const size_t str_len, ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
BLF_RESULT_CHECK_INIT(r_info);
if (font) {
return blf_font_height(font, str, str_len, r_info);
}
return 0.0f;
}
int BLF_height_max(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_font_height_max(font);
}
return 0;
}
int BLF_width_max(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_font_width_max(font);
}
return 0;
}
int BLF_descender(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_font_descender(font);
}
return 0;
}
int BLF_ascender(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
return blf_font_ascender(font);
}
return 0.0f;
}
void BLF_rotation(int fontid, float angle)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->angle = angle;
}
}
void BLF_clipping(int fontid, int xmin, int ymin, int xmax, int ymax)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->clip_rec.xmin = xmin;
font->clip_rec.ymin = ymin;
font->clip_rec.xmax = xmax;
font->clip_rec.ymax = ymax;
}
}
void BLF_wordwrap(int fontid, int wrap_width)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->wrap_width = wrap_width;
}
}
void BLF_shadow(int fontid, FontShadowType type, const float rgba[4])
{
FontBLF *font = blf_get(fontid);
if (font) {
font->shadow = type;
if (rgba) {
rgba_float_to_uchar(font->shadow_color, rgba);
}
}
}
void BLF_shadow_offset(int fontid, int x, int y)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->shadow_x = x;
font->shadow_y = y;
}
}
void BLF_buffer(int fontid, float *fbuf, uchar *cbuf, int w, int h, ColorManagedDisplay *display)
{
FontBLF *font = blf_get(fontid);
if (font) {
font->buf_info.fbuf = fbuf;
font->buf_info.cbuf = cbuf;
font->buf_info.dims[0] = w;
font->buf_info.dims[1] = h;
font->buf_info.display = display;
}
}
void BLF_buffer_col(int fontid, const float rgba[4])
{
FontBLF *font = blf_get(fontid);
if (font) {
copy_v4_v4(font->buf_info.col_init, rgba);
}
}
void blf_draw_buffer__start(FontBLF *font)
{
FontBufInfoBLF *buf_info = &font->buf_info;
rgba_float_to_uchar(buf_info->col_char, buf_info->col_init);
if (buf_info->display) {
copy_v4_v4(buf_info->col_float, buf_info->col_init);
IMB_colormanagement_display_to_scene_linear_v3(buf_info->col_float, buf_info->display);
}
else {
srgb_to_linearrgb_v4(buf_info->col_float, buf_info->col_init);
}
}
void blf_draw_buffer__end() {}
void BLF_draw_buffer(int fontid, const char *str, const size_t str_len, ResultBLF *r_info)
{
FontBLF *font = blf_get(fontid);
if (font && (font->buf_info.fbuf || font->buf_info.cbuf)) {
blf_draw_buffer__start(font);
if (font->flags & BLF_WORD_WRAP) {
blf_font_draw_buffer__wrap(font, str, str_len, r_info);
}
else {
blf_font_draw_buffer(font, str, str_len, r_info);
}
blf_draw_buffer__end();
}
}
blender::Vector<blender::StringRef> BLF_string_wrap(int fontid,
blender::StringRef str,
const int max_pixel_width)
{
FontBLF *font = blf_get(fontid);
if (!font) {
return {};
}
return blf_font_string_wrap(font, str, max_pixel_width);
}
char *BLF_display_name_from_file(const char *filepath)
{
/* While listing font directories this function can be called simultaneously from a greater
* number of threads than we want the FreeType cache to keep open at a time. Therefore open
* with a separate FT_Library object and use FreeType calls directly to avoid any contention. */
char *name = nullptr;
FT_Library ft_library;
if (FT_Init_FreeType(&ft_library) == FT_Err_Ok) {
FT_Face face;
if (FT_New_Face(ft_library, filepath, 0, &face) == FT_Err_Ok) {
if (face->family_name) {
name = BLI_sprintfN("%s %s", face->family_name, face->style_name);
}
FT_Done_Face(face);
}
FT_Done_FreeType(ft_library);
}
return name;
}
char *BLF_display_name_from_id(int fontid)
{
FontBLF *font = blf_get(fontid);
if (!font) {
return nullptr;
}
return blf_display_name(font);
}
bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, float *scale)
{
FontBLF *font = blf_get(fontid);
if (!font) {
return false;
}
if (!blf_ensure_face(font)) {
return false;
}
/* Copied without change from vfontdata_freetype.cc to ensure consistent sizing. */
/* Blender default BFont is not "complete". */
const bool complete_font = (font->face->ascender != 0) && (font->face->descender != 0) &&
(font->face->ascender != font->face->descender);
if (complete_font) {
/* We can get descender as well, but we simple store descender in relation to the ascender.
* Also note that descender is stored as a negative number. */
*ascend_ratio = float(font->face->ascender) / (font->face->ascender - font->face->descender);
}
else {
*ascend_ratio = 0.8f;
*em_ratio = 1.0f;
}
/* Adjust font size */
if (font->face->bbox.yMax != font->face->bbox.yMin) {
*scale = float(1.0 / double(font->face->bbox.yMax - font->face->bbox.yMin));
if (complete_font) {
*em_ratio = float(font->face->ascender - font->face->descender) /
(font->face->bbox.yMax - font->face->bbox.yMin);
}
}
else {
*scale = 1.0f / 1000.0f;
}
return true;
}
float BLF_character_to_curves(int fontid, uint unicode, ListBase *nurbsbase, const float scale)
{
FontBLF *font = blf_get(fontid);
if (!font) {
return 0.0f;
}
return blf_character_to_curves(font, unicode, nurbsbase, scale);
}
#ifndef NDEBUG
void BLF_state_print(int fontid)
{
FontBLF *font = blf_get(fontid);
if (font) {
printf("fontid %d %p\n", fontid, (void *)font);
printf(" mem_name: '%s'\n", font->mem_name ? font->mem_name : "<none>");
printf(" filepath: '%s'\n", font->filepath ? font->filepath : "<none>");
printf(" size: %f\n", font->size);
printf(" pos: %d %d %d\n", UNPACK3(font->pos));
printf(" aspect: (%d) %.6f %.6f %.6f\n",
(font->flags & BLF_ROTATION) != 0,
UNPACK3(font->aspect));
printf(" angle: (%d) %.6f\n", (font->flags & BLF_ASPECT) != 0, font->angle);
printf(" flag: %d\n", font->flags);
}
else {
printf("fontid %d (nullptr)\n", fontid);
}
fflush(stdout);
}
#endif