Support colored font
This commit is contained in:
parent
05b1843818
commit
c5e3acc29c
3 changed files with 59 additions and 22 deletions
|
@ -87,6 +87,6 @@ if env['builtin_freetype']:
|
||||||
|
|
||||||
# Godot source files
|
# Godot source files
|
||||||
env.add_source_files(env.modules_sources, "*.cpp")
|
env.add_source_files(env.modules_sources, "*.cpp")
|
||||||
env.Append(CCFLAGS=['-DFREETYPE_ENABLED'])
|
env.Append(CCFLAGS=['-DFREETYPE_ENABLED', '-DFT_CONFIG_OPTION_USE_PNG'])
|
||||||
|
|
||||||
Export('env')
|
Export('env')
|
||||||
|
|
|
@ -192,10 +192,25 @@ Error DynamicFontAtSize::_load() {
|
||||||
ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER );
|
ERR_FAIL_COND_V( error, ERR_INVALID_PARAMETER );
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
|
if (FT_HAS_COLOR(face)) {
|
||||||
|
int best_match = 0;
|
||||||
|
int diff = ABS(id.size - face->available_sizes[0].width);
|
||||||
|
scale_color_font = float(id.size) / face->available_sizes[0].width;
|
||||||
|
for (int i = 1; i < face->num_fixed_sizes; i++) {
|
||||||
|
int ndiff = ABS(id.size - face->available_sizes[i].width);
|
||||||
|
if (ndiff < diff) {
|
||||||
|
best_match = i;
|
||||||
|
diff = ndiff;
|
||||||
|
scale_color_font = float(id.size) / face->available_sizes[i].width;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
error = FT_Select_Size(face, best_match);
|
||||||
|
} else {
|
||||||
error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
|
error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
|
||||||
|
}
|
||||||
|
|
||||||
ascent = (face->size->metrics.ascender >> 6) / oversampling;
|
ascent = (face->size->metrics.ascender >> 6) / oversampling * scale_color_font;
|
||||||
descent = (-face->size->metrics.descender >> 6) / oversampling;
|
descent = (-face->size->metrics.descender >> 6) / oversampling * scale_color_font;
|
||||||
linegap = 0;
|
linegap = 0;
|
||||||
texture_flags = 0;
|
texture_flags = 0;
|
||||||
if (id.mipmaps)
|
if (id.mipmaps)
|
||||||
|
@ -292,7 +307,6 @@ Size2 DynamicFontAtSize::get_char_size(CharType p_char, CharType p_next, const V
|
||||||
ret.x += (delta.x >> 6) / oversampling;
|
ret.x += (delta.x >> 6) / oversampling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,14 +348,18 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
|
||||||
|
|
||||||
if (!ch->found)
|
if (!ch->found)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Point2 cpos = p_pos;
|
Point2 cpos = p_pos;
|
||||||
cpos.x += ch->h_align;
|
cpos.x += ch->h_align;
|
||||||
cpos.y -= get_ascent();
|
cpos.y -= fb->get_ascent();
|
||||||
cpos.y += ch->v_align;
|
cpos.y += ch->v_align;
|
||||||
ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= fb->textures.size(), 0);
|
ERR_FAIL_COND_V(ch->texture_idx < -1 || ch->texture_idx >= fb->textures.size(), 0);
|
||||||
if (ch->texture_idx != -1)
|
if (ch->texture_idx != -1) {
|
||||||
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect_uv, p_modulate, false, RID(), false);
|
Color modulate = p_modulate;
|
||||||
|
if (FT_HAS_COLOR(fb->face)) {
|
||||||
|
modulate.r = modulate.g = modulate.b = 1;
|
||||||
|
}
|
||||||
|
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size * Vector2(fb->scale_color_font, fb->scale_color_font)), fb->textures[ch->texture_idx].texture->get_rid(), ch->rect_uv, modulate, false, RID(), false);
|
||||||
|
}
|
||||||
advance = ch->advance;
|
advance = ch->advance;
|
||||||
used_fallback = true;
|
used_fallback = true;
|
||||||
break;
|
break;
|
||||||
|
@ -362,8 +380,13 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT
|
||||||
cpos.y -= get_ascent();
|
cpos.y -= get_ascent();
|
||||||
cpos.y += c->v_align;
|
cpos.y += c->v_align;
|
||||||
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
|
ERR_FAIL_COND_V(c->texture_idx < -1 || c->texture_idx >= textures.size(), 0);
|
||||||
if (c->texture_idx != -1)
|
if (c->texture_idx != -1) {
|
||||||
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size), textures[c->texture_idx].texture->get_rid(), c->rect_uv, p_modulate, false, RID(), false);
|
Color modulate = p_modulate;
|
||||||
|
if (FT_HAS_COLOR(face)) {
|
||||||
|
modulate.r = modulate.g = modulate.b = 1;
|
||||||
|
}
|
||||||
|
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, c->rect.size * Vector2(scale_color_font, scale_color_font)), textures[c->texture_idx].texture->get_rid(), c->rect_uv, modulate, false, RID(), false);
|
||||||
|
}
|
||||||
advance = c->advance;
|
advance = c->advance;
|
||||||
//textures[c->texture_idx].texture->draw(p_canvas_item,Vector2());
|
//textures[c->texture_idx].texture->draw(p_canvas_item,Vector2());
|
||||||
}
|
}
|
||||||
|
@ -437,9 +460,9 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
char_map[p_char] = ch;
|
char_map[p_char] = ch;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int error = FT_Load_Char(face, p_char, FT_LOAD_RENDER | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
|
int error = FT_Load_Char(face, p_char, FT_HAS_COLOR(face) ? FT_LOAD_COLOR : FT_LOAD_DEFAULT | (font->force_autohinter ? FT_LOAD_FORCE_AUTOHINT : 0));
|
||||||
if (!error) {
|
if (!error) {
|
||||||
error = FT_Render_Glyph(face->glyph, ft_render_mode_normal);
|
error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
|
||||||
}
|
}
|
||||||
if (error) {
|
if (error) {
|
||||||
|
|
||||||
|
@ -476,6 +499,8 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
|
|
||||||
//find a texture to fit this...
|
//find a texture to fit this...
|
||||||
|
|
||||||
|
int color_size = slot->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA ? 4 : 2;
|
||||||
|
Image::Format require_format = color_size == 4 ? Image::FORMAT_RGBA8 : Image::FORMAT_LA8;
|
||||||
int tex_index = -1;
|
int tex_index = -1;
|
||||||
int tex_x = 0;
|
int tex_x = 0;
|
||||||
int tex_y = 0;
|
int tex_y = 0;
|
||||||
|
@ -484,6 +509,9 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
|
|
||||||
CharTexture &ct = textures[i];
|
CharTexture &ct = textures[i];
|
||||||
|
|
||||||
|
if (ct.texture->get_format() != require_format)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture
|
if (mw > ct.texture_size || mh > ct.texture_size) //too big for this texture
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -533,13 +561,13 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
|
|
||||||
CharTexture tex;
|
CharTexture tex;
|
||||||
tex.texture_size = texsize;
|
tex.texture_size = texsize;
|
||||||
tex.imgdata.resize(texsize * texsize * 2); //grayscale alpha
|
tex.imgdata.resize(texsize * texsize * color_size);
|
||||||
|
|
||||||
{
|
{
|
||||||
//zero texture
|
//zero texture
|
||||||
PoolVector<uint8_t>::Write w = tex.imgdata.write();
|
PoolVector<uint8_t>::Write w = tex.imgdata.write();
|
||||||
ERR_FAIL_COND(texsize * texsize * 2 > tex.imgdata.size());
|
ERR_FAIL_COND(texsize * texsize * color_size > tex.imgdata.size());
|
||||||
for (int i = 0; i < texsize * texsize * 2; i++) {
|
for (int i = 0; i < texsize * texsize * color_size; i++) {
|
||||||
w[i] = 0;
|
w[i] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -561,7 +589,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
for (int i = 0; i < h; i++) {
|
for (int i = 0; i < h; i++) {
|
||||||
for (int j = 0; j < w; j++) {
|
for (int j = 0; j < w; j++) {
|
||||||
|
|
||||||
int ofs = ((i + tex_y + rect_margin) * tex.texture_size + j + tex_x + rect_margin) * 2;
|
int ofs = ((i + tex_y + rect_margin) * tex.texture_size + j + tex_x + rect_margin) * color_size;
|
||||||
ERR_FAIL_COND(ofs >= tex.imgdata.size());
|
ERR_FAIL_COND(ofs >= tex.imgdata.size());
|
||||||
switch (slot->bitmap.pixel_mode) {
|
switch (slot->bitmap.pixel_mode) {
|
||||||
case FT_PIXEL_MODE_MONO: {
|
case FT_PIXEL_MODE_MONO: {
|
||||||
|
@ -574,7 +602,14 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
wr[ofs + 0] = 255; //grayscale as 1
|
wr[ofs + 0] = 255; //grayscale as 1
|
||||||
wr[ofs + 1] = slot->bitmap.buffer[i * slot->bitmap.pitch + j];
|
wr[ofs + 1] = slot->bitmap.buffer[i * slot->bitmap.pitch + j];
|
||||||
break;
|
break;
|
||||||
// TODO: FT_PIXEL_MODE_LCD, FT_PIXEL_MODE_BGRA
|
case FT_PIXEL_MODE_BGRA: {
|
||||||
|
int ofs_color = i * slot->bitmap.pitch + (j << 2);
|
||||||
|
wr[ofs + 2] = slot->bitmap.buffer[ofs_color + 0];
|
||||||
|
wr[ofs + 1] = slot->bitmap.buffer[ofs_color + 1];
|
||||||
|
wr[ofs + 0] = slot->bitmap.buffer[ofs_color + 2];
|
||||||
|
wr[ofs + 3] = slot->bitmap.buffer[ofs_color + 3];
|
||||||
|
} break;
|
||||||
|
// TODO: FT_PIXEL_MODE_LCD
|
||||||
default:
|
default:
|
||||||
ERR_EXPLAIN("Font uses unsupported pixel format: " + itos(slot->bitmap.pixel_mode));
|
ERR_EXPLAIN("Font uses unsupported pixel format: " + itos(slot->bitmap.pixel_mode));
|
||||||
ERR_FAIL();
|
ERR_FAIL();
|
||||||
|
@ -587,7 +622,7 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
//blit to image and texture
|
//blit to image and texture
|
||||||
{
|
{
|
||||||
|
|
||||||
Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, Image::FORMAT_LA8, tex.imgdata));
|
Ref<Image> img = memnew(Image(tex.texture_size, tex.texture_size, 0, require_format, tex.imgdata));
|
||||||
|
|
||||||
if (tex.texture.is_null()) {
|
if (tex.texture.is_null()) {
|
||||||
tex.texture.instance();
|
tex.texture.instance();
|
||||||
|
@ -605,9 +640,9 @@ void DynamicFontAtSize::_update_char(CharType p_char) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Character chr;
|
Character chr;
|
||||||
chr.h_align = xofs / oversampling;
|
chr.h_align = xofs * scale_color_font / oversampling;
|
||||||
chr.v_align = ascent - (yofs / oversampling); // + ascent - descent;
|
chr.v_align = ascent - (yofs * scale_color_font / oversampling); // + ascent - descent;
|
||||||
chr.advance = advance / oversampling;
|
chr.advance = advance * scale_color_font / oversampling;
|
||||||
chr.texture_idx = tex_index;
|
chr.texture_idx = tex_index;
|
||||||
chr.found = true;
|
chr.found = true;
|
||||||
|
|
||||||
|
@ -646,6 +681,7 @@ DynamicFontAtSize::DynamicFontAtSize() {
|
||||||
linegap = 1;
|
linegap = 1;
|
||||||
texture_flags = 0;
|
texture_flags = 0;
|
||||||
oversampling = font_oversampling;
|
oversampling = font_oversampling;
|
||||||
|
scale_color_font = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DynamicFontAtSize::~DynamicFontAtSize() {
|
DynamicFontAtSize::~DynamicFontAtSize() {
|
||||||
|
|
|
@ -104,6 +104,7 @@ class DynamicFontAtSize : public Reference {
|
||||||
float linegap;
|
float linegap;
|
||||||
float rect_margin;
|
float rect_margin;
|
||||||
float oversampling;
|
float oversampling;
|
||||||
|
float scale_color_font;
|
||||||
|
|
||||||
uint32_t texture_flags;
|
uint32_t texture_flags;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue