diff options
Diffstat (limited to 'source/blender/blenfont/intern')
-rw-r--r-- | source/blender/blenfont/intern/blf.c | 3 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_font.c | 53 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_glyph.c | 230 | ||||
-rw-r--r-- | source/blender/blenfont/intern/blf_internal_types.h | 47 |
4 files changed, 137 insertions, 196 deletions
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 2b592c9e550..725c4c0712d 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -584,9 +584,6 @@ static void blf_draw_gl__start(FontBLF *font) * in BLF_position (old ui_rasterpos_safe). */ - /* always bind the texture for the first glyph */ - font->tex_bind_state = 0; - if ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0) { return; /* glyphs will be translated individually and batched. */ } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 25ea0770f8b..f0afe184233 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -84,16 +84,19 @@ 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.offset_loc = GPU_vertformat_attr_add(&format, "offset", GPU_COMP_I32, 1, GPU_FETCH_INT); + g_batch.glyph_size_loc = GPU_vertformat_attr_add( + &format, "glyph_size", GPU_COMP_I32, 2, GPU_FETCH_INT); 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); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step); g_batch.glyph_len = 0; /* A dummy vbo containing 4 points, attribs are not used. */ @@ -177,6 +180,46 @@ void blf_batch_draw_begin(FontBLF *font) } } +static GPUTexture *blf_batch_cache_texture_load(void) +{ + GlyphCacheBLF *gc = g_batch.glyph_cache; + BLI_assert(gc); + BLI_assert(gc->bitmap_len > 0); + + if (gc->bitmap_len > gc->bitmap_len_landed) { + const int tex_width = GPU_texture_width(gc->texture); + + int bitmap_len_landed = gc->bitmap_len_landed; + int remain = gc->bitmap_len - bitmap_len_landed; + int offset_x = bitmap_len_landed % tex_width; + int offset_y = bitmap_len_landed / tex_width; + + /* TODO(germano): Update more than one row in a single call. */ + while (remain) { + int remain_row = tex_width - offset_x; + int width = remain > remain_row ? remain_row : remain; + GPU_texture_update_sub(gc->texture, + GPU_DATA_UNSIGNED_BYTE, + &gc->bitmap_result[bitmap_len_landed], + offset_x, + offset_y, + 0, + width, + 1, + 0); + + bitmap_len_landed += width; + remain -= width; + offset_x = 0; + offset_y += 1; + } + + gc->bitmap_len_landed = bitmap_len_landed; + } + + return gc->texture; +} + void blf_batch_draw(void) { if (g_batch.glyph_len == 0) { @@ -190,7 +233,8 @@ void blf_batch_draw(void) /* 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); + GPUTexture *texture = blf_batch_cache_texture_load(); + GPU_texture_bind(texture, 0); GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len); GPU_vertbuf_use(g_batch.verts); /* send data */ @@ -202,8 +246,9 @@ void blf_batch_draw(void) /* 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); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step); + GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step); g_batch.glyph_len = 0; } diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 80d43a49e77..8e88bda37a5 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -143,13 +143,6 @@ 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 = (GPUTexture **)MEM_callocN(sizeof(GPUTexture *) * 256, __func__); - gc->textures_len = 256; - gc->texture_current = BLF_TEXTURE_UNSET; - 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; gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f; @@ -173,9 +166,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) CLAMP_MIN(gc->glyph_width_max, 1); CLAMP_MIN(gc->glyph_height_max, 1); - gc->p2_width = 0; - gc->p2_height = 0; - BLI_addhead(&font->cache, gc); return gc; } @@ -229,52 +219,13 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) blf_glyph_free(g); } } - for (i = 0; i < gc->textures_len; i++) { - if (gc->textures[i]) { - GPU_texture_free(gc->textures[i]); - } + if (gc->texture) { + GPU_texture_free(gc->texture); } - MEM_freeN(gc->textures); - MEM_freeN(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_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))); - if (gc->p2_width > font->tex_size_max) { - gc->p2_width = font->tex_size_max; + if (gc->bitmap_result) { + MEM_freeN(gc->bitmap_result); } - - 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->pad * 2))); - - if (gc->p2_height > font->tex_size_max) { - gc->p2_height = font->tex_size_max; - } - - GPUTexture *tex = GPU_texture_create_nD( - gc->p2_width, gc->p2_height, 0, 2, NULL, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, error); - - GPU_texture_bind(tex, 0); - GPU_texture_wrap_mode(tex, false); - GPU_texture_filters(tex, GPU_NEAREST, GPU_LINEAR); - GPU_texture_clear(tex, GPU_DATA_UNSIGNED_BYTE, NULL); - GPU_texture_unbind(tex); - - gc->textures[gc->texture_current] = tex; + MEM_freeN(gc); } GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) @@ -377,8 +328,6 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add"); g->c = c; g->idx = (FT_UInt)index; - g->offset_x = -1; - g->offset_y = -1; bitmap = slot->bitmap; g->width = (int)bitmap.width; g->height = (int)bitmap.rows; @@ -418,17 +367,19 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un 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) { MEM_freeN(g->bitmap); } MEM_freeN(g); } -static void blf_texture_draw( - const unsigned char color[4], const float uv[2][2], float x1, float y1, float x2, float y2) +static void blf_texture_draw(const unsigned char color[4], + const int glyph_size[2], + const int offset, + float x1, + float y1, + float x2, + float y2) { /* 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 */ @@ -437,8 +388,10 @@ static void blf_texture_draw( 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); + copy_v2_v2_int(GPU_vertbuf_raw_step(&g_batch.glyph_size_step), glyph_size); + *((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = offset; + g_batch.glyph_len++; /* Flush cache if it's full. */ if (g_batch.glyph_len == BLF_BATCH_DRAW_LEN_MAX) { @@ -447,45 +400,35 @@ static void blf_texture_draw( } static void blf_texture5_draw(const unsigned char color_in[4], - int tex_w, - int tex_h, - const float uv[2][2], + const int glyph_size[2], + const int offset, float x1, float y1, float x2, float y2) { - float ofs[2] = {2 / (float)tex_w, 2 / (float)tex_h}; - float uv_flag[2][2]; - copy_v4_v4((float *)uv_flag, (float *)uv); + int glyph_size_flag[2]; /* flag the x and y component signs for 5x5 blurring */ - 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]); + glyph_size_flag[0] = -glyph_size[0]; + glyph_size_flag[1] = -glyph_size[1]; - blf_texture_draw(color_in, uv_flag, x1 - 2, y1 + 2, x2 + 2, y2 - 2); + blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2); } static void blf_texture3_draw(const unsigned char color_in[4], - int tex_w, - int tex_h, - const float uv[2][2], + const int glyph_size[2], + const int offset, float x1, float y1, float x2, float y2) { - float ofs[2] = {1 / (float)tex_w, 1 / (float)tex_h}; - float uv_flag[2][2]; - copy_v4_v4((float *)uv_flag, (float *)uv); + int glyph_size_flag[2]; /* flag the x component sign for 3x3 blurring */ - 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]); + glyph_size_flag[0] = -glyph_size[0]; + glyph_size_flag[1] = glyph_size[1]; - blf_texture_draw(color_in, uv_flag, x1 - 1, y1 + 1, x2 + 1, y2 - 1); + blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2); } static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) @@ -518,63 +461,38 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl return; } - if (g->build_tex == 0) { + if (!g->cached) { if (font->tex_size_max == -1) { 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 = 3; /* enough padding for blur */ - } + g->offset = gc->bitmap_len; - if (gc->offset_x > (gc->p2_width - gc->glyph_width_max)) { - gc->offset_x = gc->pad; - gc->offset_y += gc->glyph_height_max; + int buff_size = g->width * g->height; + int bitmap_len = gc->bitmap_len + buff_size; - if (gc->offset_y > (gc->p2_height - gc->glyph_height_max)) { - gc->offset_y = 3; /* enough padding for blur */ - blf_glyph_cache_texture(font, gc); - } - } + if (bitmap_len > gc->bitmap_len_alloc) { + int w = font->tex_size_max; + int h = bitmap_len / w + 1; - g->tex = gc->textures[gc->texture_current]; - g->offset_x = gc->offset_x; - g->offset_y = gc->offset_y; + gc->bitmap_len_alloc = w * h; + gc->bitmap_result = MEM_reallocN(gc->bitmap_result, (size_t)gc->bitmap_len_alloc); - /* prevent glTexSubImage2D from failing if the character - * asks for pixels out of bounds, this tends only to happen - * with very small sizes (5px high or less) */ - if (UNLIKELY((g->offset_x + g->width) > gc->p2_width)) { - g->width -= (g->offset_x + g->width) - gc->p2_width; - BLI_assert(g->width > 0); - } - if (UNLIKELY((g->offset_y + g->height) > gc->p2_height)) { - g->height -= (g->offset_y + g->height) - gc->p2_height; - BLI_assert(g->height > 0); - } - - GPU_texture_update_sub(g->tex, - GPU_DATA_UNSIGNED_BYTE, - g->bitmap, - g->offset_x, - g->offset_y, - 0, - g->width, - g->height, - 0); + /* Keep in sync with the texture. */ + if (gc->texture) { + GPU_texture_free(gc->texture); + } + gc->texture = GPU_texture_create_nD( + w, h, 0, 1, NULL, GPU_R8, GPU_DATA_UNSIGNED_BYTE, 0, false, NULL); - g->uv[0][0] = ((float)g->offset_x) / ((float)gc->p2_width); - g->uv[0][1] = ((float)g->offset_y) / ((float)gc->p2_height); - g->uv[1][0] = ((float)(g->offset_x + g->width)) / ((float)gc->p2_width); - g->uv[1][1] = ((float)(g->offset_y + g->height)) / ((float)gc->p2_height); + gc->bitmap_len_landed = 0; + } - /* update the x offset for the next glyph. */ - gc->offset_x += (int)BLI_rctf_size_x(&g->box) + gc->pad; + memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, (size_t)buff_size); + gc->bitmap_len = bitmap_len; gc->glyphs_len_free--; - g->build_tex = 1; + g->cached = true; } if (font->flags & BLF_CLIPPING) { @@ -587,27 +505,26 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl } } - if (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; + g_batch.glyph_cache = gc; + BLI_assert(g->offset < gc->bitmap_len); if (font->flags & BLF_SHADOW) { rctf rect_ofs; blf_glyph_calc_rect_shadow(&rect_ofs, g, x, y, font); if (font->shadow == 0) { - blf_texture_draw( - font->shadow_color, g->uv, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + blf_texture_draw(font->shadow_color, + (int[2]){g->width, g->height}, + g->offset, + rect_ofs.xmin, + rect_ofs.ymin, + rect_ofs.xmax, + rect_ofs.ymax); } else if (font->shadow <= 4) { blf_texture3_draw(font->shadow_color, - gc->p2_width, - gc->p2_height, - g->uv, + (int[2]){g->width, g->height}, + g->offset, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, @@ -615,9 +532,8 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl } else { blf_texture5_draw(font->shadow_color, - gc->p2_width, - gc->p2_height, - g->uv, + (int[2]){g->width, g->height}, + g->offset, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, @@ -632,9 +548,8 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl switch (font->blur) { case 3: blf_texture3_draw(font->color, - gc->p2_width, - gc->p2_height, - g->uv, + (int[2]){g->width, g->height}, + g->offset, rect.xmin, rect.ymin, rect.xmax, @@ -642,18 +557,29 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl break; case 5: blf_texture5_draw(font->color, - gc->p2_width, - gc->p2_height, - g->uv, + (int[2]){g->width, g->height}, + g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; default: - blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture_draw(font->color, + (int[2]){g->width, g->height}, + g->offset, + rect.xmin, + rect.ymin, + rect.xmax, + rect.ymax); } #else - blf_texture_draw(font->color, g->uv, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + blf_texture_draw(font->color, + (int[2]){g->width, g->height}, + g->offset, + rect.xmin, + rect.ymin, + rect.xmax, + rect.ymax); #endif } diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 45086de0f61..bb1697d7860 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -33,13 +33,13 @@ 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; + struct GPUVertBufRaw pos_step, col_step, offset_step, glyph_size_step; + unsigned int pos_loc, col_loc, offset_loc, glyph_size_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; + struct GlyphCacheBLF *glyph_cache; } BatchBLF; extern BatchBLF g_batch; @@ -72,30 +72,16 @@ typedef struct GlyphCacheBLF { struct GlyphBLF *glyph_ascii_table[256]; /* texture array, to draw the glyphs. */ - GPUTexture **textures; - - /* size of the array. */ - unsigned int textures_len; - - /* and the last texture, aka. the current texture. */ - unsigned int texture_current; - - /* We draw every glyph in a big texture, so this is the - * current position inside the texture. */ - int offset_x; - int offset_y; - - /* and the space from one to other. */ - int pad; + GPUTexture *texture; + char *bitmap_result; + int bitmap_len; + int bitmap_len_landed; + int bitmap_len_alloc; /* and the bigger glyph in the font. */ int glyph_width_max; int glyph_height_max; - /* next two integer power of two, to build the texture. */ - int p2_width; - int p2_height; - /* number of glyphs in the font. */ int glyphs_len_max; @@ -125,12 +111,8 @@ typedef struct GlyphBLF { /* avoid conversion to int while drawing */ int advance_i; - /* texture id where this glyph is store. */ - GPUTexture *tex; - /* position inside the texture where this glyph is store. */ - int offset_x; - int offset_y; + int offset; /* Bitmap data, from freetype. Take care that this * can be NULL. @@ -142,9 +124,6 @@ typedef struct GlyphBLF { int height; int pitch; - /* uv coords. */ - float uv[2][2]; - /* X and Y bearing of the glyph. * The X bearing is from the origin to the glyph left bbox edge. * The Y bearing is from the baseline to the top of the glyph edge. @@ -152,8 +131,7 @@ typedef struct GlyphBLF { float pos_x; float pos_y; - /* with value of zero mean that we need build the texture. */ - char build_tex; + bool cached; } GlyphBLF; typedef struct FontBufInfoBLF { @@ -239,9 +217,6 @@ typedef struct FontBLF { /* max texture size. */ int tex_size_max; - /* cache current OpenGL texture to save calls into the API */ - GPUTexture *tex_bind_state; - /* font options. */ int flags; @@ -286,6 +261,4 @@ typedef struct DirBLF { char *path; } DirBLF; -#define BLF_TEXTURE_UNSET ((unsigned int)-1) - #endif /* __BLF_INTERNAL_TYPES_H__ */ |