diff options
Diffstat (limited to 'source/blender/blenfont/intern/blf_glyph.c')
-rw-r--r-- | source/blender/blenfont/intern/blf_glyph.c | 269 |
1 files changed, 144 insertions, 125 deletions
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 9af347908e1..84388bedb7b 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_2D(gc->p2_width, gc->p2_height, GPU_R8, (const float *)pixels, 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) @@ -296,8 +344,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; @@ -325,79 +373,54 @@ 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(GWN_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(GWN_vertbuf_raw_step(&g_batch.tex_step), (float *)uv); + copy_v4_v4_uchar(GWN_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) @@ -419,12 +442,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)) { @@ -432,7 +455,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); } } @@ -453,15 +476,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, 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); @@ -488,42 +503,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 } |