diff options
Diffstat (limited to 'source/blender/blenfont')
-rw-r--r-- | source/blender/blenfont/BLF_api.h | 41 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf.c | 259 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_font.c | 262 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_glyph.c | 273 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_internal.h | 8 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_internal_types.h | 54 |
6 files changed, 610 insertions, 287 deletions
diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 9bb3dd39aa6..f9ad1de8015 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -35,6 +35,9 @@ #include "BLI_compiler_attrs.h" #include "BLI_sys_types.h" +/* enable this only if needed (unused circa 2016) */ +#define BLF_BLUR_ENABLE 0 + struct rctf; struct ColorManagedDisplay; struct ResultBLF; @@ -43,6 +46,8 @@ int BLF_init(void); void BLF_exit(void); void BLF_default_dpi(int dpi); void BLF_default_set(int fontid); +int BLF_default(void); /* get default font ID so we can pass it to other functions */ +void BLF_batch_reset(void); /* call when changing opengl context. */ void BLF_cache_clear(void); @@ -62,6 +67,17 @@ void BLF_aspect(int fontid, float x, float y, float z); void BLF_position(int fontid, float x, float y, float z); void BLF_size(int fontid, int size, int dpi); +/* goal: small but useful color API */ +void BLF_color4ubv(int fontid, const unsigned char rgba[4]); +void BLF_color3ubv(int fontid, const unsigned char rgb[3]); +void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha); +void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b); +void BLF_color4f(int fontid, float r, float g, float b, float a); +void BLF_color4fv(int fontid, const float rgba[4]); +void BLF_color3f(int fontid, float r, float g, float b); +void BLF_color3fv_alpha(int fontid, const float rgb[3], float alpha); +/* also available: UI_FontThemeColor(fontid, colorid) */ + /* Set a 4x4 matrix to be multiplied before draw the text. * Remember that you need call BLF_enable(BLF_MATRIX) * to enable this. @@ -76,6 +92,12 @@ void BLF_size(int fontid, int size, int dpi); */ void BLF_matrix(int fontid, const float m[16]); +/* Batch drawcalls together as long as + * the modelview matrix and the font remain unchanged. */ +void BLF_batch_draw_begin(void); +void BLF_batch_draw_flush(void); +void BLF_batch_draw_end(void); + /* Draw the string using the default font, size and dpi. */ void BLF_draw_default(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL(); void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL(); @@ -123,29 +145,16 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt */ float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT; -/* and this two function return the width and height - * of the string, using the default font and both value - * are multiplied by the aspect of the font. - */ -void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height) ATTR_NONNULL(); -float BLF_width_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -float BLF_height_default(const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); - -/* Set rotation for default font. */ -void BLF_rotation_default(float angle); - -/* Enable/disable options to the default font. */ -void BLF_enable_default(int option); -void BLF_disable_default(int option); - /* By default, rotation and clipping are disable and * have to be enable/disable using BLF_enable/disable. */ void BLF_rotation(int fontid, float angle); void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax); -void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax); void BLF_wordwrap(int fontid, int wrap_width); + +#if BLF_BLUR_ENABLE void BLF_blur(int fontid, int size); +#endif void BLF_enable(int fontid, int option); void BLF_disable(int fontid, int option); diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 75aabf1f713..8e3f42e4d27 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -50,13 +50,14 @@ #include "BLI_math.h" #include "BLI_threads.h" -#include "BIF_gl.h" #include "BLF_api.h" #include "IMB_colormanagement.h" #ifndef BLF_STANDALONE -#include "GPU_basic_shader.h" +#include "GPU_shader.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" #endif #include "blf_internal_types.h" @@ -130,6 +131,11 @@ void BLF_exit(void) blf_font_exit(); } +void BLF_batch_reset(void) +{ + blf_batch_draw_vao_clear(); +} + void BLF_cache_clear(void) { FontBLF *font; @@ -137,8 +143,10 @@ void BLF_cache_clear(void) for (i = 0; i < BLF_MAX_FONT; i++) { font = global_font[i]; - if (font) + if (font) { blf_glyph_cache_clear(font); + blf_kerning_cache_clear(font); + } } } @@ -175,6 +183,12 @@ void BLF_default_set(int fontid) } } +int BLF_default(void) +{ + ASSERT_DEFAULT_SET; + return global_font_default; +} + int BLF_load(const char *name) { FontBLF *font; @@ -358,24 +372,6 @@ void BLF_disable(int fontid, int option) } } -void BLF_enable_default(int option) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->flags |= option; - } -} - -void BLF_disable_default(int option) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->flags &= ~option; - } -} - void BLF_aspect(int fontid, float x, float y, float z) { FontBLF *font = blf_get(fontid); @@ -454,6 +450,7 @@ void BLF_size(int fontid, int size, int dpi) } } +#if BLF_BLUR_ENABLE void BLF_blur(int fontid, int size) { FontBLF *font = blf_get(fontid); @@ -462,6 +459,97 @@ void BLF_blur(int fontid, int size) font->blur = size; } } +#endif + +void BLF_color4ubv(int fontid, const unsigned char 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 unsigned char rgb[3], unsigned char 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 unsigned char rgb[3]) +{ + BLF_color3ubv_alpha(fontid, rgb, 255); +} + +void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char 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) +{ + 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) +{ + float rgba[4] = { r, g, b, 1.0f }; + BLF_color4fv(fontid, rgba); +} + +void BLF_batch_draw_begin(void) +{ + BLI_assert(g_batch.enabled == false); + g_batch.enabled = true; +} + +void BLF_batch_draw_flush(void) +{ + if (g_batch.enabled) { + blf_batch_draw(); + } +} + +void BLF_batch_draw_end(void) +{ + BLI_assert(g_batch.enabled == true); + blf_batch_draw(); /* Draw remaining glyphs */ + g_batch.enabled = false; +} void BLF_draw_default(float x, float y, float z, const char *str, size_t len) { @@ -482,72 +570,37 @@ void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t l BLF_draw_ascii(global_font_default, str, len); /* XXX, use real length */ } -void BLF_rotation_default(float angle) -{ - FontBLF *font = blf_get(global_font_default); - - if (font) { - font->angle = angle; - } -} - -static void blf_draw_gl__start(FontBLF *font, GLint *mode) +static void blf_draw_gl__start(FontBLF *font) { /* * The pixmap alignment hack is handle * in BLF_position (old ui_rasterpos_safe). */ - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - -#ifndef BLF_STANDALONE - GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR); -#endif - - /* Save the current matrix mode. */ - glGetIntegerv(GL_MATRIX_MODE, mode); + /* always bind the texture for the first glyph */ + font->tex_bind_state = 0; - glMatrixMode(GL_TEXTURE); - glPushMatrix(); - glLoadIdentity(); + if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0) + return; /* glyphs will be translated individually and batched. */ - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); + GPU_matrix_push(); if (font->flags & BLF_MATRIX) - glMultMatrixf(font->m); + GPU_matrix_mul(font->m); - glTranslate3fv(font->pos); + GPU_matrix_translate_3fv(font->pos); if (font->flags & BLF_ASPECT) - glScalef(font->aspect[0], font->aspect[1], font->aspect[2]); - - if (font->flags & BLF_ROTATION) /* radians -> degrees */ - glRotatef(font->angle * (float)(180.0 / M_PI), 0.0f, 0.0f, 1.0f); + GPU_matrix_scale_3fv(font->aspect); - if (font->shadow || font->blur) - glGetFloatv(GL_CURRENT_COLOR, font->orig_col); - - /* always bind the texture for the first glyph */ - font->tex_bind_state = -1; + if (font->flags & BLF_ROTATION) + GPU_matrix_rotate_2d(RAD2DEG(font->angle)); } -static void blf_draw_gl__end(GLint mode) +static void blf_draw_gl__end(FontBLF *font) { - glMatrixMode(GL_TEXTURE); - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - - if (mode != GL_MODELVIEW) - glMatrixMode(mode); - -#ifndef BLF_STANDALONE - GPU_basic_shader_bind(GPU_SHADER_USE_COLOR); -#endif - glDisable(GL_BLEND); + if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) != 0) + GPU_matrix_pop(); } void BLF_draw_ex( @@ -555,23 +608,26 @@ void BLF_draw_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { blf_font_draw__wrap(font, str, len, r_info); } else { blf_font_draw(font, str, len, r_info); } - blf_draw_gl__end(mode); + blf_draw_gl__end(font); } } void BLF_draw(int fontid, const char *str, size_t len) { + if (len == 0 || str[0] == '\0') { + return; + } + BLF_draw_ex(fontid, str, len, NULL); } @@ -580,12 +636,11 @@ void BLF_draw_ascii_ex( struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); - GLint mode; BLF_RESULT_CHECK_INIT(r_info); if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); if (font->flags & BLF_WORD_WRAP) { /* use non-ascii draw function for word-wrap */ blf_font_draw__wrap(font, str, len, r_info); @@ -593,24 +648,31 @@ void BLF_draw_ascii_ex( else { blf_font_draw_ascii(font, str, len, r_info); } - blf_draw_gl__end(mode); + blf_draw_gl__end(font); } } void BLF_draw_ascii(int fontid, const char *str, size_t len) { + if (len == 0 || str[0] == '\0') { + return; + } + BLF_draw_ascii_ex(fontid, str, len, NULL); } int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) { + if (len == 0 || str[0] == '\0') { + return 0; + } + FontBLF *font = blf_get(fontid); - GLint mode; int columns = 0; if (font && font->glyph_cache) { - blf_draw_gl__start(font, &mode); + blf_draw_gl__start(font); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw_gl__end(mode); + blf_draw_gl__end(font); } return columns; @@ -690,14 +752,6 @@ void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_widt } } -void BLF_width_and_height_default(const char *str, size_t len, float *r_width, float *r_height) -{ - ASSERT_DEFAULT_SET; - - BLF_size(global_font_default, global_font_points, global_font_dpi); - BLF_width_and_height(global_font_default, str, len, r_width, r_height); -} - float BLF_width_ex( int fontid, const char *str, size_t len, struct ResultBLF *r_info) @@ -728,14 +782,6 @@ float BLF_fixed_width(int fontid) return 0.0f; } -float BLF_width_default(const char *str, size_t len) -{ - ASSERT_DEFAULT_SET; - - BLF_size(global_font_default, global_font_points, global_font_dpi); - return BLF_width(global_font_default, str, len); -} - float BLF_height_ex( int fontid, const char *str, size_t len, struct ResultBLF *r_info) @@ -799,15 +845,6 @@ float BLF_ascender(int fontid) return 0.0f; } -float BLF_height_default(const char *str, size_t len) -{ - ASSERT_DEFAULT_SET; - - BLF_size(global_font_default, global_font_points, global_font_dpi); - - return BLF_height(global_font_default, str, len); -} - void BLF_rotation(int fontid, float angle) { FontBLF *font = blf_get(fontid); @@ -829,18 +866,6 @@ void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax) } } -void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax) -{ - FontBLF *font = blf_get(global_font_default); - - 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); @@ -856,7 +881,7 @@ void BLF_shadow(int fontid, int level, const float rgba[4]) if (font) { font->shadow = level; - copy_v4_v4(font->shadow_col, rgba); + rgba_float_to_uchar(font->shadow_color, rgba); } } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index fe9769dd2d1..f7a926275a9 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -58,6 +58,12 @@ #include "BIF_gl.h" #include "BLF_api.h" +#include "UI_interface.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" +#include "GPU_batch.h" + #include "blf_internal_types.h" #include "blf_internal.h" @@ -67,12 +73,155 @@ # define FT_New_Face FT_New_Face__win32_compat #endif +/* Batching buffer for drawing. */ +BatchBLF g_batch; + /* freetype2 handle ONLY for this file!. */ static FT_Library ft_lib; static SpinLock ft_lib_mutex; +/* -------------------------------------------------------------------- */ +/** \name Glyph Batching + * \{ */ +/** + * Drawcalls are precious! make them count! + * Since most of the Text elems are not covered by other UI elements, we can + * group some strings together and render them in one drawcall. This behaviour + * is on demand only, between BLF_batch_start() and BLF_batch_end(). + **/ +static void blf_batch_draw_init(void) +{ + GPUVertFormat format = {0}; + g_batch.pos_loc = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + g_batch.tex_loc = GPU_vertformat_attr_add(&format, "tex", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + g_batch.col_loc = GPU_vertformat_attr_add(&format, "col", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + g_batch.verts = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STREAM); + GPU_vertbuf_data_alloc(g_batch.verts, BLF_BATCH_DRAW_LEN_MAX); + + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step); + g_batch.glyph_len = 0; + + g_batch.batch = GPU_batch_create_ex(GPU_PRIM_POINTS, g_batch.verts, NULL, GPU_BATCH_OWNS_VBO); +} + +static void blf_batch_draw_exit(void) +{ + GPU_BATCH_DISCARD_SAFE(g_batch.batch); +} + +void blf_batch_draw_vao_clear(void) +{ + if (g_batch.batch) { + GPU_batch_vao_cache_clear(g_batch.batch); + } +} + +void blf_batch_draw_begin(FontBLF *font) +{ + if (g_batch.batch == NULL) { + blf_batch_draw_init(); + } + + const bool font_changed = (g_batch.font != font); + const bool simple_shader = ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0); + const bool shader_changed = (simple_shader != g_batch.simple_shader); + + g_batch.active = g_batch.enabled && simple_shader; + + if (simple_shader) { + /* Offset is applied to each glyph. */ + g_batch.ofs[0] = floorf(font->pos[0]); + g_batch.ofs[1] = floorf(font->pos[1]); + } + else { + /* Offset is baked in modelview mat. */ + zero_v2(g_batch.ofs); + } + + if (g_batch.active) { + float gpumat[4][4]; + GPU_matrix_model_view_get(gpumat); + + bool mat_changed = (memcmp(gpumat, g_batch.mat, sizeof(g_batch.mat)) != 0); + + if (mat_changed) { + /* Modelviewmat is no longer the same. + * Flush cache but with the previous mat. */ + GPU_matrix_push(); + GPU_matrix_set(g_batch.mat); + } + + /* flush cache if config is not the same. */ + if (mat_changed || font_changed || shader_changed) { + blf_batch_draw(); + g_batch.simple_shader = simple_shader; + g_batch.font = font; + } + else { + /* Nothing changed continue batching. */ + return; + } + + if (mat_changed) { + GPU_matrix_pop(); + /* Save for next memcmp. */ + memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat)); + } + } + else { + /* flush cache */ + blf_batch_draw(); + g_batch.font = font; + g_batch.simple_shader = simple_shader; + } +} + +void blf_batch_draw(void) +{ + if (g_batch.glyph_len == 0) + return; + + GPU_blend(true); + GPU_blend_set_func_separate(GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); + + /* We need to flush widget base first to ensure correct ordering. */ + UI_widgetbase_draw_cache_flush(); + + GPU_texture_bind(g_batch.tex_bind_state, 0); + GPU_vertbuf_vertex_count_set(g_batch.verts, g_batch.glyph_len); + GPU_vertbuf_use(g_batch.verts); /* send data */ + + GPUBuiltinShader shader = (g_batch.simple_shader) ? GPU_SHADER_TEXT_SIMPLE : GPU_SHADER_TEXT; + GPU_batch_program_set_builtin(g_batch.batch, shader); + GPU_batch_uniform_1i(g_batch.batch, "glyph", 0); + GPU_batch_draw(g_batch.batch); + + GPU_blend(false); + + /* restart to 1st vertex data pointers */ + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.tex_loc, &g_batch.tex_step); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step); + g_batch.glyph_len = 0; +} + +static void blf_batch_draw_end(void) +{ + if (!g_batch.active) { + blf_batch_draw(); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + int blf_font_init(void) { + memset(&g_batch, 0, sizeof(g_batch)); BLI_spin_init(&ft_lib_mutex); return FT_Init_FreeType(&ft_lib); } @@ -81,6 +230,7 @@ void blf_font_exit(void) { FT_Done_FreeType(ft_lib); BLI_spin_end(&ft_lib_mutex); + blf_batch_draw_exit(); } void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) @@ -88,6 +238,14 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) GlyphCacheBLF *gc; FT_Error err; + gc = blf_glyph_cache_find(font, size, dpi); + if (gc) { + font->glyph_cache = gc; + /* Optimization: do not call FT_Set_Char_Size if size did not change. */ + if (font->size == size && font->dpi == dpi) + return; + } + err = FT_Set_Char_Size(font->face, 0, (FT_F26Dot6)(size * 64), dpi, dpi); if (err) { /* FIXME: here we can go through the fixed size and choice a close one */ @@ -98,10 +256,7 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) font->size = size; font->dpi = dpi; - gc = blf_glyph_cache_find(font, size, dpi); - if (gc) - font->glyph_cache = gc; - else { + if (!gc) { gc = blf_glyph_cache_new(font); if (gc) font->glyph_cache = gc; @@ -129,6 +284,20 @@ static void blf_font_ensure_ascii_table(FontBLF *font) } } +static void blf_font_ensure_ascii_kerning(FontBLF *font, const FT_UInt kern_mode) +{ + KerningCacheBLF *kc = font->kerning_cache; + + font->kerning_mode = kern_mode; + + if (!kc || kc->mode != kern_mode) { + font->kerning_cache = kc = blf_kerning_cache_find(font); + if (!kc) { + font->kerning_cache = kc = blf_kerning_cache_new(font); + } + } +} + /* Fast path for runs of ASCII characters. Given that common UTF-8 * input will consist of an overwhelming majority of ASCII * characters. @@ -156,6 +325,26 @@ static void blf_font_ensure_ascii_table(FontBLF *font) (((_font)->flags & BLF_KERNING_DEFAULT) ? \ ft_kerning_default : (FT_UInt)FT_KERNING_UNFITTED) \ +/* Note, + * blf_font_ensure_ascii_kerning(font, kern_mode); must be called before this macro */ + +#define BLF_KERNING_STEP_FAST(_font, _kern_mode, _g_prev, _g, _c_prev, _c, _pen_x) \ +{ \ + if (_g_prev) { \ + FT_Vector _delta; \ + if (_c_prev < 0x80 && _c < 0x80) { \ + _pen_x += (_font)->kerning_cache->table[_c][_c_prev]; \ + } \ + else if (FT_Get_Kerning((_font)->face, \ + (_g_prev)->idx, \ + (_g)->idx, \ + _kern_mode, \ + &(_delta)) == 0) \ + { \ + _pen_x += (int)_delta.x >> 6; \ + } \ + } \ +} (void)0 #define BLF_KERNING_STEP(_font, _kern_mode, _g_prev, _g, _delta, _pen_x) \ { \ @@ -176,16 +365,23 @@ static void blf_font_draw_ex( FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) { - unsigned int c; + unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; - FT_Vector delta; int pen_x = 0; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; + if (len == 0) { + /* early output, don't do any IMM OpenGL. */ + return; + } + BLF_KERNING_VARS(font, has_kerning, kern_mode); blf_font_ensure_ascii_table(font); + blf_font_ensure_ascii_kerning(font, kern_mode); + + blf_batch_draw_begin(font); while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -195,15 +391,18 @@ static void blf_font_draw_ex( if (UNLIKELY(g == NULL)) continue; if (has_kerning) - BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); /* do not return this loop if clipped, we want every character tested */ blf_glyph_render(font, g, (float)pen_x, (float)pen_y); pen_x += g->advance_i; g_prev = g; + c_prev = c; } + blf_batch_draw_end(); + if (r_info) { r_info->lines = 1; r_info->width = pen_x; @@ -219,30 +418,35 @@ static void blf_font_draw_ascii_ex( FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) { - unsigned char c; + unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; - FT_Vector delta; int pen_x = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; BLF_KERNING_VARS(font, has_kerning, kern_mode); blf_font_ensure_ascii_table(font); + blf_font_ensure_ascii_kerning(font, kern_mode); + + blf_batch_draw_begin(font); while ((c = *(str++)) && len--) { BLI_assert(c < 128); if ((g = glyph_ascii_table[c]) == NULL) continue; if (has_kerning) - BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); /* do not return this loop if clipped, we want every character tested */ blf_glyph_render(font, g, (float)pen_x, (float)pen_y); pen_x += g->advance_i; g_prev = g; + c_prev = c; } + blf_batch_draw_end(); + if (r_info) { r_info->lines = 1; r_info->width = pen_x; @@ -265,6 +469,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) blf_font_ensure_ascii_table(font); + blf_batch_draw_begin(font); + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -284,6 +490,8 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) pen_x += cwidth * col; } + blf_batch_draw_end(); + return columns; } @@ -292,9 +500,8 @@ static void blf_font_draw_buffer_ex( FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y) { - unsigned int c; + unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; - FT_Vector delta; int pen_x = (int)font->pos[0]; int pen_y_basis = (int)font->pos[1] + pen_y; size_t i = 0; @@ -310,6 +517,7 @@ static void blf_font_draw_buffer_ex( BLF_KERNING_VARS(font, has_kerning, kern_mode); blf_font_ensure_ascii_table(font); + blf_font_ensure_ascii_kerning(font, kern_mode); /* another buffer specific call for color conversion */ @@ -321,7 +529,7 @@ static void blf_font_draw_buffer_ex( if (UNLIKELY(g == NULL)) continue; if (has_kerning) - BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); chx = pen_x + ((int)g->pos_x); chy = pen_y_basis + g->height; @@ -423,6 +631,7 @@ static void blf_font_draw_buffer_ex( pen_x += g->advance_i; g_prev = g; + c_prev = c; } if (r_info) { @@ -444,7 +653,7 @@ size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, floa int pen_x = 0; size_t i = 0, i_prev; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; - const int width_i = (int)width + 1; + const int width_i = (int)width; int width_new; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -466,7 +675,7 @@ size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, floa pen_x += g->advance_i; - if (width_i < pen_x) { + if (width_i <= pen_x) { break; } @@ -570,9 +779,8 @@ static void blf_font_boundbox_ex( FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info, int pen_y) { - unsigned int c; + unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; - FT_Vector delta; int pen_x = 0; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; @@ -587,6 +795,7 @@ static void blf_font_boundbox_ex( box->ymax = -32000.0f; blf_font_ensure_ascii_table(font); + blf_font_ensure_ascii_kerning(font, kern_mode); while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); @@ -596,7 +805,7 @@ static void blf_font_boundbox_ex( if (UNLIKELY(g == NULL)) continue; if (has_kerning) - BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x); gbox.xmin = (float)pen_x; gbox.xmax = (float)pen_x + g->advance; @@ -611,6 +820,7 @@ static void blf_font_boundbox_ex( pen_x += g->advance_i; g_prev = g; + c_prev = c; } if (box->xmin > box->xmax) { @@ -891,6 +1101,8 @@ void blf_font_free(FontBLF *font) blf_glyph_cache_free(gc); } + blf_kerning_cache_clear(font); + FT_Done_Face(font->face); if (font->filename) MEM_freeN(font->filename); @@ -901,8 +1113,6 @@ void blf_font_free(FontBLF *font) static void blf_font_fill(FontBLF *font) { - unsigned int i; - font->aspect[0] = 1.0f; font->aspect[1] = 1.0f; font->aspect[2] = 1.0f; @@ -910,9 +1120,15 @@ static void blf_font_fill(FontBLF *font) font->pos[1] = 0.0f; font->angle = 0.0f; - for (i = 0; i < 16; i++) + for (int i = 0; i < 16; i++) font->m[i] = 0; + /* annoying bright color so we can see where to add BLF_color calls */ + font->color[0] = 255; + font->color[1] = 255; + font->color[2] = 0; + font->color[3] = 255; + font->clip_rec.xmin = 0.0f; font->clip_rec.xmax = 0.0f; font->clip_rec.ymin = 0.0f; @@ -921,8 +1137,12 @@ static void blf_font_fill(FontBLF *font) font->dpi = 0; font->size = 0; BLI_listbase_clear(&font->cache); + BLI_listbase_clear(&font->kerning_caches); font->glyph_cache = NULL; + font->kerning_cache = NULL; +#if BLF_BLUR_ENABLE font->blur = 0; +#endif font->tex_size_max = -1; font->buf_info.fbuf = NULL; diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index f1301d38ab6..5b1a382e368 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -56,13 +56,69 @@ #include "BLF_api.h" #ifndef BLF_STANDALONE -# include "GPU_basic_shader.h" +# include "GPU_immediate.h" +# include "GPU_extensions.h" #endif #include "blf_internal_types.h" #include "blf_internal.h" #include "BLI_strict_flags.h" +#include "BLI_math_vector.h" + +KerningCacheBLF *blf_kerning_cache_find(FontBLF *font) +{ + KerningCacheBLF *p; + + p = (KerningCacheBLF *)font->kerning_caches.first; + while (p) { + if (p->mode == font->kerning_mode) + return p; + p = p->next; + } + return NULL; +} + +/* Create a new glyph cache for the current kerning mode. */ +KerningCacheBLF *blf_kerning_cache_new(FontBLF *font) +{ + KerningCacheBLF *kc; + + kc = (KerningCacheBLF *)MEM_callocN(sizeof(KerningCacheBLF), "blf_kerning_cache_new"); + kc->next = NULL; + kc->prev = NULL; + kc->mode = font->kerning_mode; + + unsigned int i, j; + for (i = 0; i < 0x80; i++) { + for (j = 0; j < 0x80; j++) { + GlyphBLF *g = blf_glyph_search(font->glyph_cache, i); + if (!g) { + FT_UInt glyph_index = FT_Get_Char_Index(font->face, i); + g = blf_glyph_add(font, glyph_index, i); + } + /* Cannot fail since it has been added just before. */ + GlyphBLF *g_prev = blf_glyph_search(font->glyph_cache, j); + + FT_Vector delta = {.x = 0, .y = 0}; + if (FT_Get_Kerning(font->face, g_prev->idx, g->idx, kc->mode, &delta) == 0) { + kc->table[i][j] = (int)delta.x >> 6; + } + else { + kc->table[i][j] = 0; + } + } + } + + BLI_addhead(&font->kerning_caches, kc); + return kc; +} + +void blf_kerning_cache_clear(FontBLF *font) +{ + font->kerning_cache = NULL; + BLI_freelistN(&font->kerning_caches); +} GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) { @@ -91,12 +147,12 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table)); memset(gc->bucket, 0, sizeof(gc->bucket)); - gc->textures = (GLuint *)MEM_mallocN(sizeof(GLuint) * 256, __func__); + gc->textures = (GPUTexture **)MEM_callocN(sizeof(GPUTexture *) * 256, __func__); gc->textures_len = 256; gc->texture_current = BLF_TEXTURE_UNSET; - gc->offset_x = 0; - gc->offset_y = 0; - gc->pad = 3; + gc->offset_x = 3; /* enough padding for blur */ + gc->offset_y = 3; /* enough padding for blur */ + gc->pad = 6; gc->glyphs_len_max = (int)font->face->num_glyphs; gc->glyphs_len_free = (int)font->face->num_glyphs; @@ -141,16 +197,17 @@ void blf_glyph_cache_clear(FontBLF *font) void blf_glyph_cache_free(GlyphCacheBLF *gc) { GlyphBLF *g; - int i; + unsigned int i; for (i = 0; i < 257; i++) { while ((g = BLI_pophead(&gc->bucket[i]))) { blf_glyph_free(g); } } - - if (gc->texture_current != BLF_TEXTURE_UNSET) { - glDeleteTextures((int)gc->texture_current + 1, gc->textures); + for (i = 0; i < gc->textures_len; i++) { + if (gc->textures[i]) { + GPU_texture_free(gc->textures[i]); + } } MEM_freeN(gc->textures); MEM_freeN(gc); @@ -159,13 +216,14 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) { int i; + char error[256]; /* move the index. */ gc->texture_current++; if (UNLIKELY(gc->texture_current >= gc->textures_len)) { gc->textures_len *= 2; - gc->textures = MEM_reallocN((void *)gc->textures, sizeof(GLuint) * gc->textures_len); + gc->textures = MEM_recallocN((void *)gc->textures, sizeof(GPUTexture *) * gc->textures_len); } gc->p2_width = (int)blf_next_p2((unsigned int)((gc->glyphs_len_free * gc->glyph_width_max) + (gc->pad * 2))); @@ -174,30 +232,20 @@ static void blf_glyph_cache_texture(FontBLF *font, GlyphCacheBLF *gc) } i = (int)((gc->p2_width - (gc->pad * 2)) / gc->glyph_width_max); - gc->p2_height = (int)blf_next_p2((unsigned int)(((gc->glyphs_len_max / i) + 1) * gc->glyph_height_max)); + gc->p2_height = (int)blf_next_p2((unsigned int)(((gc->glyphs_len_max / i) + 1) * gc->glyph_height_max + (gc->pad * 2))); if (gc->p2_height > font->tex_size_max) { gc->p2_height = font->tex_size_max; } - glGenTextures(1, &gc->textures[gc->texture_current]); - glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = gc->textures[gc->texture_current])); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - -#ifndef BLF_STANDALONE - /* needed since basic shader doesn't support alpha-only textures, - * while we could add support this is only used in a few places - * (an alternative could be to have a simple shader for BLF). */ - if (GLEW_ARB_texture_swizzle && GPU_basic_shader_use_glsl_get()) { - GLint swizzle_mask[] = {GL_ONE, GL_ONE, GL_ONE, GL_ALPHA}; - glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle_mask); - } -#endif - - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, gc->p2_width, gc->p2_height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, NULL); + unsigned char *pixels = MEM_callocN((size_t)gc->p2_width * (size_t)gc->p2_height, "BLF texture init"); + GPUTexture *tex = GPU_texture_create_nD(gc->p2_width, gc->p2_height, 0, 2, pixels, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, error); + MEM_freeN(pixels); + gc->textures[gc->texture_current] = tex; + GPU_texture_bind(tex, 0); + GPU_texture_wrap_mode(tex, false); + GPU_texture_filters(tex, GPU_NEAREST, GPU_LINEAR); + GPU_texture_unbind(tex); } GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) @@ -297,8 +345,8 @@ GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c) } } - g->bitmap = (unsigned char *)MEM_mallocN((size_t)(g->width * g->height), "glyph bitmap"); - memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)(g->width * g->height)); + g->bitmap = (unsigned char *)MEM_mallocN((size_t)g->width * (size_t)g->height, "glyph bitmap"); + memcpy((void *)g->bitmap, (void *)bitmap.buffer, (size_t)g->width * (size_t)g->height); } g->advance = ((float)slot->advance.x) / 64.0f; @@ -326,87 +374,62 @@ void blf_glyph_free(GlyphBLF *g) /* don't need free the texture, the GlyphCache already * have a list of all the texture and free it. */ - if (g->bitmap) { + if (g->bitmap) MEM_freeN(g->bitmap); - } MEM_freeN(g); } -static void blf_texture_draw(float uv[2][2], float dx, float y1, float dx1, float y2) +static void blf_texture_draw(const unsigned char color[4], const float uv[2][2], float x1, float y1, float x2, float y2) { - glBegin(GL_QUADS); - glTexCoord2f(uv[0][0], uv[0][1]); - glVertex2f(dx, y1); - - glTexCoord2f(uv[0][0], uv[1][1]); - glVertex2f(dx, y2); - - glTexCoord2f(uv[1][0], uv[1][1]); - glVertex2f(dx1, y2); - - glTexCoord2f(uv[1][0], uv[0][1]); - glVertex2f(dx1, y1); - glEnd(); + /* 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 */ + copy_v4_fl4(GPU_vertbuf_raw_step(&g_batch.pos_step), x1 + g_batch.ofs[0], y1 + g_batch.ofs[1], + x2 + g_batch.ofs[0], y2 + g_batch.ofs[1]); + copy_v4_v4(GPU_vertbuf_raw_step(&g_batch.tex_step), (float *)uv); + copy_v4_v4_uchar(GPU_vertbuf_raw_step(&g_batch.col_step), color); + g_batch.glyph_len++; + /* Flush cache if it's full. */ + if (g_batch.glyph_len == BLF_BATCH_DRAW_LEN_MAX) { + blf_batch_draw(); + } } -static void blf_texture5_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture5_draw(const unsigned char color_in[4], int tex_w, int tex_h, const float uv[2][2], + float x1, float y1, float x2, float y2) { - const float soft[25] = {1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f, - 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f, - 2 / 60.0f, 5 / 60.0f, 8 / 60.0f, 5 / 60.0f, 2 / 60.0f, - 1 / 60.0f, 3 / 60.0f, 5 / 60.0f, 3 / 60.0f, 1 / 60.0f, - 1 / 60.0f, 1 / 60.0f, 2 / 60.0f, 1 / 60.0f, 1 / 60.0f}; - - const float *fp = soft; - float color[4]; - float dx, dy; - - color[0] = shadow_col[0]; - color[1] = shadow_col[1]; - color[2] = shadow_col[2]; - - for (dx = -2; dx < 3; dx++) { - for (dy = -2; dy < 3; dy++, fp++) { - color[3] = *(fp) * shadow_col[3]; - glColor4fv(color); - blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); - } - } - - glColor4fv(color); + float ofs[2] = { 2 / (float)tex_w, 2 / (float)tex_h }; + float uv_flag[2][2]; + copy_v4_v4((float *)uv_flag, (float *)uv); + /* flag the x and y component signs for 5x5 bluring */ + uv_flag[0][0] = -(uv_flag[0][0] - ofs[0]); + uv_flag[0][1] = -(uv_flag[0][1] - ofs[1]); + uv_flag[1][0] = -(uv_flag[1][0] + ofs[0]); + uv_flag[1][1] = -(uv_flag[1][1] + ofs[1]); + + blf_texture_draw(color_in, uv_flag, x1 - 2, y1 + 2, x2 + 2, y2 - 2); } -static void blf_texture3_draw(const float shadow_col[4], float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture3_draw(const unsigned char color_in[4], int tex_w, int tex_h, const float uv[2][2], + float x1, float y1, float x2, float y2) { - const float soft[9] = {1 / 16.0f, 2 / 16.0f, 1 / 16.0f, - 2 / 16.0f, 4 / 16.0f, 2 / 16.0f, - 1 / 16.0f, 2 / 16.0f, 1 / 16.0f}; - - const float *fp = soft; - float color[4]; - float dx, dy; - - color[0] = shadow_col[0]; - color[1] = shadow_col[1]; - color[2] = shadow_col[2]; - - for (dx = -1; dx < 2; dx++) { - for (dy = -1; dy < 2; dy++, fp++) { - color[3] = *(fp) * shadow_col[3]; - glColor4fv(color); - blf_texture_draw(uv, x1 + dx, y1 + dy, x2 + dx, y2 + dy); - } - } - - glColor4fv(color); + float ofs[2] = { 1 / (float)tex_w, 1 / (float)tex_h }; + float uv_flag[2][2]; + copy_v4_v4((float *)uv_flag, (float *)uv); + /* flag the x component sign for 3x3 bluring */ + uv_flag[0][0] = -(uv_flag[0][0] - ofs[0]); + uv_flag[0][1] = (uv_flag[0][1] - ofs[1]); + uv_flag[1][0] = -(uv_flag[1][0] + ofs[0]); + uv_flag[1][1] = (uv_flag[1][1] + ofs[1]); + + blf_texture_draw(color_in, uv_flag, x1 - 1, y1 + 1, x2 + 1, y2 - 1); } static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) { rect->xmin = floorf(x + g->pos_x); rect->xmax = rect->xmin + (float)g->width; - rect->ymin = y + g->pos_y; - rect->ymax = y + g->pos_y - (float)g->height; + rect->ymin = floorf(y + g->pos_y); + rect->ymax = rect->ymin - (float)g->height; } void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) @@ -420,12 +443,12 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) GlyphCacheBLF *gc = font->glyph_cache; if (font->tex_size_max == -1) - glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&font->tex_size_max); + font->tex_size_max = GPU_max_texture_size(); if (gc->texture_current == BLF_TEXTURE_UNSET) { blf_glyph_cache_texture(font, gc); gc->offset_x = gc->pad; - gc->offset_y = 0; + gc->offset_y = 3; /* enough padding for blur */ } if (gc->offset_x > (gc->p2_width - gc->glyph_width_max)) { @@ -433,7 +456,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) gc->offset_y += gc->glyph_height_max; if (gc->offset_y > (gc->p2_height - gc->glyph_height_max)) { - gc->offset_y = 0; + gc->offset_y = 3; /* enough padding for blur */ blf_glyph_cache_texture(font, gc); } } @@ -454,15 +477,7 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) BLI_assert(g->height > 0); } - - glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); - glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); - glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); - - glBindTexture(GL_TEXTURE_2D, g->tex); - glTexSubImage2D(GL_TEXTURE_2D, 0, g->offset_x, g->offset_y, g->width, g->height, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap); - glPopClientAttrib(); + GPU_texture_update_sub(g->tex, GPU_DATA_UNSIGNED_BYTE, g->bitmap, g->offset_x, g->offset_y, 0, g->width, g->height, 0); g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width); g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height); @@ -489,42 +504,46 @@ void blf_glyph_render(FontBLF *font, GlyphBLF *g, float x, float y) } if (font->tex_bind_state != g->tex) { - glBindTexture(GL_TEXTURE_2D, (font->tex_bind_state = g->tex)); + blf_batch_draw(); + font->tex_bind_state = g->tex; + GPU_texture_bind(font->tex_bind_state, 0); } + g_batch.tex_bind_state = g->tex; + if (font->flags & BLF_SHADOW) { rctf rect_ofs; blf_glyph_calc_rect(&rect_ofs, g, x + (float)font->shadow_x, y + (float)font->shadow_y); - switch (font->shadow) { - case 3: - blf_texture3_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; - case 5: - blf_texture5_draw(font->shadow_col, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; - default: - glColor4fv(font->shadow_col); - blf_texture_draw(g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); - break; + if (font->shadow == 0) { + blf_texture_draw(font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + } + else if (font->shadow <= 4) { + blf_texture3_draw(font->shadow_color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv, + rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + } + else { + blf_texture5_draw(font->shadow_color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv, + rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); } - - glColor4fv(font->orig_col); } +#if BLF_BLUR_ENABLE switch (font->blur) { case 3: - blf_texture3_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture3_draw(font->color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv, + rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; case 5: - blf_texture5_draw(font->orig_col, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture5_draw(font->color, font->glyph_cache->p2_width, font->glyph_cache->p2_height, g->uv, + rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; default: - blf_texture_draw(g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - break; + blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); } - - return; +#else + blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); +#endif } diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 708466e8ebd..624f3ae884c 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -37,6 +37,10 @@ struct GlyphBLF; struct GlyphCacheBLF; struct rctf; +void blf_batch_draw_vao_clear(void); +void blf_batch_draw_begin(struct FontBLF *font); +void blf_batch_draw(void); + unsigned int blf_next_p2(unsigned int x); unsigned int blf_hash(unsigned int val); @@ -74,6 +78,10 @@ int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const si void blf_font_free(struct FontBLF *font); +struct KerningCacheBLF *blf_kerning_cache_find(struct FontBLF *font); +struct KerningCacheBLF *blf_kerning_cache_new(struct FontBLF *font); +void blf_kerning_cache_clear(struct FontBLF *font); + struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, unsigned int size, unsigned int dpi); struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font); void blf_glyph_cache_clear(struct FontBLF *font); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 5723f08d44b..265835f4c75 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -31,6 +31,37 @@ #ifndef __BLF_INTERNAL_TYPES_H__ #define __BLF_INTERNAL_TYPES_H__ +#include "GPU_vertex_buffer.h" +#include "GPU_texture.h" + +#define BLF_BATCH_DRAW_LEN_MAX 2048 /* in glyph */ + +typedef struct BatchBLF { + struct FontBLF *font; /* can only batch glyph from the same font */ + struct GPUBatch *batch; + struct GPUVertBuf *verts; + struct GPUVertBufRaw pos_step, tex_step, col_step; + unsigned int pos_loc, tex_loc, col_loc; + unsigned int glyph_len; + float ofs[2]; /* copy of font->pos */ + float mat[4][4]; /* previous call modelmatrix. */ + bool enabled, active, simple_shader; + GPUTexture *tex_bind_state; +} BatchBLF; + +extern BatchBLF g_batch; + +typedef struct KerningCacheBLF { + struct KerningCacheBLF *next, *prev; + + /* kerning mode. */ + FT_UInt mode; + + /* only cache a ascii glyph pairs. Only store the x + * offset we are interested in, instead of the full FT_Vector. */ + int table[0x80][0x80]; +} KerningCacheBLF; + typedef struct GlyphCacheBLF { struct GlyphCacheBLF *next; struct GlyphCacheBLF *prev; @@ -48,7 +79,7 @@ typedef struct GlyphCacheBLF { struct GlyphBLF *glyph_ascii_table[256]; /* texture array, to draw the glyphs. */ - unsigned int *textures; + GPUTexture **textures; /* size of the array. */ unsigned int textures_len; @@ -103,7 +134,7 @@ typedef struct GlyphBLF { int advance_i; /* texture id where this glyph is store. */ - unsigned int tex; + GPUTexture *tex; /* position inside the texture where this glyph is store. */ int offset_x; @@ -175,8 +206,10 @@ typedef struct FontBLF { /* angle in radians. */ float angle; +#if 0 /* BLF_BLUR_ENABLE */ /* blur: 3 or 5 large kernel */ int blur; +#endif /* shadow level. */ int shadow; @@ -186,10 +219,10 @@ typedef struct FontBLF { int shadow_y; /* shadow color. */ - float shadow_col[4]; + unsigned char shadow_color[4]; - /* store color here when drawing shadow or blur. */ - float orig_col[4]; + /* main text color. */ + unsigned char color[4]; /* Multiplied this matrix with the current one before * draw the text! see blf_draw__start. @@ -212,7 +245,7 @@ typedef struct FontBLF { int tex_size_max; /* cache current OpenGL texture to save calls into the API */ - unsigned int tex_bind_state; + GPUTexture *tex_bind_state; /* font options. */ int flags; @@ -223,6 +256,12 @@ typedef struct FontBLF { /* current glyph cache, size and dpi. */ GlyphCacheBLF *glyph_cache; + /* list of kerning cache for this font. */ + ListBase kerning_caches; + + /* current kerning cache for this font and kerning mode. */ + KerningCacheBLF *kerning_cache; + /* freetype2 lib handle. */ FT_Library ft_lib; @@ -232,6 +271,9 @@ typedef struct FontBLF { /* freetype2 face. */ FT_Face face; + /* freetype kerning */ + FT_UInt kerning_mode; + /* data for buffer usage (drawing into a texture buffer) */ FontBufInfoBLF buf_info; } FontBLF; |