diff options
Diffstat (limited to 'source')
-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 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_text_frag.glsl | 119 | ||||
-rw-r--r-- | source/blender/gpu/shaders/gpu_shader_text_vert.glsl | 21 |
6 files changed, 242 insertions, 231 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__ */ diff --git a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl index f9f195c31d6..554596fa9ae 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_frag.glsl @@ -1,9 +1,13 @@ flat in vec4 color_flat; noperspective in vec2 texCoord_interp; +flat in int glyph_offset; +flat in ivec2 glyph_dim; +flat in int interp_size; + out vec4 fragColor; -uniform sampler2D glyph; +uniform sampler1DArray glyph; const vec2 offsets4[4] = vec2[4]( vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(-0.5, -0.5), vec2(-0.5, -0.5)); @@ -25,54 +29,107 @@ const vec2 offsets16[16] = vec2[16](vec2(-1.5, 1.5), vec2(0.5, -1.5), vec2(1.5, -1.5)); -#define sample_glyph_offset(texco, texel, ofs) texture(glyph, texco + ofs * texel).r +//#define GPU_NEAREST +#define sample_glyph_offset(texel, ofs) texture_1D_custom_bilinear_filter(texCoord_interp + ofs * texel) + +float texel_fetch(int index) +{ + int size_x = textureSize(glyph, 0).r; + if (index >= size_x) { + return texelFetch(glyph, ivec2(index % size_x, index / size_x), 0).r; + } + return texelFetch(glyph, ivec2(index, 0), 0).r; +} + +bool is_inside_box(ivec2 v) +{ + return all(greaterThanEqual(v, ivec2(0))) && all(lessThan(v, glyph_dim)); +} + +float texture_1D_custom_bilinear_filter(vec2 uv) +{ + vec2 texel_2d = uv * glyph_dim + 0.5; + ivec2 texel_2d_near = ivec2(texel_2d) - 1; + int frag_offset = glyph_offset + texel_2d_near.y * glyph_dim.x + texel_2d_near.x; + + float tl = 0.0; + + if (is_inside_box(texel_2d_near)) { + tl = texel_fetch(frag_offset); + } + +#ifdef GPU_NEAREST + return tl; +#else //GPU_LINEAR + int offset_x = 1; + int offset_y = glyph_dim.x; + + float tr = 0.0; + float bl = 0.0; + float br = 0.0; + + if (is_inside_box(texel_2d_near + ivec2(1, 0))) { + tr = texel_fetch(frag_offset + offset_x); + } + if (is_inside_box(texel_2d_near + ivec2(0, 1))) { + bl = texel_fetch(frag_offset + offset_y); + } + if (is_inside_box(texel_2d_near + ivec2(1, 1))) { + br = texel_fetch(frag_offset + offset_x + offset_y); + } + + vec2 f = fract(texel_2d); + float tA = mix(tl, tr, f.x); + float tB = mix(bl, br, f.x); + + return mix(tA, tB, f.y); +#endif +} void main() { // input color replaces texture color fragColor.rgb = color_flat.rgb; - vec2 texel = 1.0 / vec2(textureSize(glyph, 0)); - vec2 texco = abs(texCoord_interp); - // modulate input alpha & texture alpha - if (texCoord_interp.x > 0) { - fragColor.a = texture(glyph, texco).r; + if (interp_size == 0) { + fragColor.a = texture_1D_custom_bilinear_filter(texCoord_interp); } else { + vec2 texel = 1.0 / glyph_dim; fragColor.a = 0.0; - if (texCoord_interp.y > 0) { + if (interp_size == 1) { /* 3x3 blur */ /* Manual unroll for perf. (stupid glsl compiler) */ - fragColor.a += sample_glyph_offset(texco, texel, offsets4[0]); - fragColor.a += sample_glyph_offset(texco, texel, offsets4[1]); - fragColor.a += sample_glyph_offset(texco, texel, offsets4[2]); - fragColor.a += sample_glyph_offset(texco, texel, offsets4[3]); + fragColor.a += sample_glyph_offset(texel, offsets4[0]); + fragColor.a += sample_glyph_offset(texel, offsets4[1]); + fragColor.a += sample_glyph_offset(texel, offsets4[2]); + fragColor.a += sample_glyph_offset(texel, offsets4[3]); fragColor.a *= (1.0 / 4.0); } else { /* 5x5 blur */ /* Manual unroll for perf. (stupid glsl compiler) */ - fragColor.a += sample_glyph_offset(texco, texel, offsets16[0]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[1]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[2]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[3]); - - fragColor.a += sample_glyph_offset(texco, texel, offsets16[4]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[5]) * 2.0; - fragColor.a += sample_glyph_offset(texco, texel, offsets16[6]) * 2.0; - fragColor.a += sample_glyph_offset(texco, texel, offsets16[7]); - - fragColor.a += sample_glyph_offset(texco, texel, offsets16[8]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[9]) * 2.0; - fragColor.a += sample_glyph_offset(texco, texel, offsets16[10]) * 2.0; - fragColor.a += sample_glyph_offset(texco, texel, offsets16[11]); - - fragColor.a += sample_glyph_offset(texco, texel, offsets16[12]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[13]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[14]); - fragColor.a += sample_glyph_offset(texco, texel, offsets16[15]); + fragColor.a += sample_glyph_offset(texel, offsets16[0]); + fragColor.a += sample_glyph_offset(texel, offsets16[1]); + fragColor.a += sample_glyph_offset(texel, offsets16[2]); + fragColor.a += sample_glyph_offset(texel, offsets16[3]); + + fragColor.a += sample_glyph_offset(texel, offsets16[4]); + fragColor.a += sample_glyph_offset(texel, offsets16[5]) * 2.0; + fragColor.a += sample_glyph_offset(texel, offsets16[6]) * 2.0; + fragColor.a += sample_glyph_offset(texel, offsets16[7]); + + fragColor.a += sample_glyph_offset(texel, offsets16[8]); + fragColor.a += sample_glyph_offset(texel, offsets16[9]) * 2.0; + fragColor.a += sample_glyph_offset(texel, offsets16[10]) * 2.0; + fragColor.a += sample_glyph_offset(texel, offsets16[11]); + + fragColor.a += sample_glyph_offset(texel, offsets16[12]); + fragColor.a += sample_glyph_offset(texel, offsets16[13]); + fragColor.a += sample_glyph_offset(texel, offsets16[14]); + fragColor.a += sample_glyph_offset(texel, offsets16[15]); fragColor.a *= (1.0 / 20.0); } } diff --git a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl index 28437208e91..768638e5229 100644 --- a/source/blender/gpu/shaders/gpu_shader_text_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_text_vert.glsl @@ -2,20 +2,33 @@ uniform mat4 ModelViewProjectionMatrix; in vec4 pos; /* rect */ -in vec4 tex; /* rect */ in vec4 col; +in int offset; +in ivec2 glyph_size; flat out vec4 color_flat; noperspective out vec2 texCoord_interp; +flat out int glyph_offset; +flat out ivec2 glyph_dim; +flat out int interp_size; void main() { + color_flat = col; + glyph_offset = offset; + glyph_dim = abs(glyph_size); + interp_size = int(glyph_size.x < 0) + int(glyph_size.y < 0); + /* Quad expension using instanced rendering. */ float x = float(gl_VertexID % 2); float y = float(gl_VertexID / 2); vec2 quad = vec2(x, y); - gl_Position = ModelViewProjectionMatrix * vec4(mix(pos.xy, pos.zw, quad), 0.0, 1.0); - texCoord_interp = mix(abs(tex.xy), abs(tex.zw), quad) * sign(tex.xw); - color_flat = col; + vec2 interp_offset = float(interp_size) / abs(pos.zw - pos.xy); + texCoord_interp = mix(-interp_offset, 1.0 + interp_offset, quad); + + vec2 final_pos = mix( + pos.xy + ivec2(-interp_size, interp_size), pos.zw + ivec2(interp_size, -interp_size), quad); + + gl_Position = ModelViewProjectionMatrix * vec4(final_pos, 0.0, 1.0); } |