Merge pull request #52890 from bruvzg/rtl_effects_connected
Improve connected grapheme handling in the RTL CharFX.
This commit is contained in:
commit
8085affdb1
9 changed files with 136 additions and 30 deletions
|
@ -28,6 +28,12 @@
|
|||
<member name="font" type="RID" setter="set_font" getter="get_font">
|
||||
Font resource used to render glyph.
|
||||
</member>
|
||||
<member name="glyph_count" type="int" setter="set_glyph_count" getter="get_glyph_count" default="0">
|
||||
Number of glyphs in the grapheme cluster. This value is set in the first glyph of a cluster. Setting this property won't affect drawing.
|
||||
</member>
|
||||
<member name="glyph_flags" type="int" setter="set_glyph_flags" getter="get_glyph_flags" default="0">
|
||||
Glyph flags. See [enum TextServer.GraphemeFlag] for more info. Setting this property won't affect drawing.
|
||||
</member>
|
||||
<member name="glyph_index" type="int" setter="set_glyph_index" getter="get_glyph_index" default="0">
|
||||
Font specific glyph index.
|
||||
</member>
|
||||
|
|
|
@ -1247,6 +1247,12 @@
|
|||
<constant name="GRAPHEME_IS_PUNCTUATION" value="256" enum="GraphemeFlag">
|
||||
Grapheme is punctuation character.
|
||||
</constant>
|
||||
<constant name="GRAPHEME_IS_UNDERSCORE" value="512" enum="GraphemeFlag">
|
||||
Grapheme is underscore character.
|
||||
</constant>
|
||||
<constant name="GRAPHEME_IS_CONNECTED" value="1024" enum="GraphemeFlag">
|
||||
Grapheme is connected to the previous grapheme. Breaking line before this grapheme is not safe.
|
||||
</constant>
|
||||
<constant name="HINTING_NONE" value="0" enum="Hinting">
|
||||
Disables font hinting (smoother but less crisp).
|
||||
</constant>
|
||||
|
|
|
@ -3804,7 +3804,12 @@ bool TextServerAdvanced::shaped_text_update_breaks(RID p_shaped) {
|
|||
gl.font_rid = sd_glyphs[i].font_rid;
|
||||
gl.font_size = sd_glyphs[i].font_size;
|
||||
gl.flags = GRAPHEME_IS_BREAK_SOFT | GRAPHEME_IS_VIRTUAL;
|
||||
sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
|
||||
if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) {
|
||||
gl.flags |= GRAPHEME_IS_RTL;
|
||||
sd->glyphs.insert(i, gl); // Insert before.
|
||||
} else {
|
||||
sd->glyphs.insert(i + sd_glyphs[i].count, gl); // Insert after.
|
||||
}
|
||||
|
||||
// Update write pointer and size.
|
||||
sd_size = sd->glyphs.size();
|
||||
|
@ -3998,7 +4003,12 @@ bool TextServerAdvanced::shaped_text_update_justification_ops(RID p_shaped) {
|
|||
gl.font_rid = sd->glyphs[i].font_rid;
|
||||
gl.font_size = sd->glyphs[i].font_size;
|
||||
gl.flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_VIRTUAL;
|
||||
sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
|
||||
if (sd->glyphs[i].flags & GRAPHEME_IS_RTL) {
|
||||
gl.flags |= GRAPHEME_IS_RTL;
|
||||
sd->glyphs.insert(i, gl); // Insert before.
|
||||
} else {
|
||||
sd->glyphs.insert(i + sd->glyphs[i].count, gl); // Insert after.
|
||||
}
|
||||
i += sd->glyphs[i].count;
|
||||
continue;
|
||||
}
|
||||
|
@ -4147,7 +4157,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
|||
}
|
||||
}
|
||||
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
|
||||
w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
|
||||
w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
|
||||
}
|
||||
if (last_cluster_valid) {
|
||||
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
|
||||
|
@ -4169,6 +4179,10 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
|||
gl.font_rid = p_fonts[p_fb_index];
|
||||
gl.font_size = fs;
|
||||
|
||||
if (glyph_info[i].mask & HB_GLYPH_FLAG_DEFINED) {
|
||||
gl.flags |= GRAPHEME_IS_CONNECTED;
|
||||
}
|
||||
|
||||
gl.index = glyph_info[i].codepoint;
|
||||
if (gl.index != 0) {
|
||||
real_t scale = font_get_scale(f, fs);
|
||||
|
@ -4199,7 +4213,7 @@ void TextServerAdvanced::_shape_run(ShapedTextDataAdvanced *p_sd, int32_t p_star
|
|||
}
|
||||
w[last_cluster_index].count = glyph_count - last_cluster_index;
|
||||
if (p_direction == HB_DIRECTION_RTL || p_direction == HB_DIRECTION_BTT) {
|
||||
w[last_cluster_index].flags |= TextServer::GRAPHEME_IS_RTL;
|
||||
w[last_cluster_index].flags |= GRAPHEME_IS_RTL;
|
||||
}
|
||||
if (last_cluster_valid) {
|
||||
w[last_cluster_index].flags |= GRAPHEME_IS_VALID;
|
||||
|
|
|
@ -90,6 +90,12 @@ void CharFXTransform::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("get_glyph_index"), &CharFXTransform::get_glyph_index);
|
||||
ClassDB::bind_method(D_METHOD("set_glyph_index", "glyph_index"), &CharFXTransform::set_glyph_index);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_glyph_count"), &CharFXTransform::get_glyph_count);
|
||||
ClassDB::bind_method(D_METHOD("set_glyph_count", "glyph_count"), &CharFXTransform::set_glyph_count);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_glyph_flags"), &CharFXTransform::get_glyph_flags);
|
||||
ClassDB::bind_method(D_METHOD("set_glyph_flags", "glyph_flags"), &CharFXTransform::set_glyph_flags);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_font"), &CharFXTransform::get_font);
|
||||
ClassDB::bind_method(D_METHOD("set_font", "font"), &CharFXTransform::set_font);
|
||||
|
||||
|
@ -101,5 +107,7 @@ void CharFXTransform::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "color"), "set_color", "get_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "env"), "set_environment", "get_environment");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_index"), "set_glyph_index", "get_glyph_index");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_count"), "set_glyph_count", "get_glyph_count");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "glyph_flags"), "set_glyph_flags", "get_glyph_flags");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::RID, "font"), "set_font", "get_font");
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
double elapsed_time = 0.0f;
|
||||
Dictionary environment;
|
||||
uint32_t glyph_index = 0;
|
||||
uint16_t glyph_flags = 0;
|
||||
uint8_t glyph_count = 0;
|
||||
RID font;
|
||||
|
||||
CharFXTransform();
|
||||
|
@ -57,19 +59,31 @@ public:
|
|||
|
||||
Vector2i get_range() { return range; }
|
||||
void set_range(const Vector2i &p_range) { range = p_range; }
|
||||
|
||||
double get_elapsed_time() { return elapsed_time; }
|
||||
void set_elapsed_time(double p_elapsed_time) { elapsed_time = p_elapsed_time; }
|
||||
|
||||
bool is_visible() { return visibility; }
|
||||
void set_visibility(bool p_visibility) { visibility = p_visibility; }
|
||||
|
||||
bool is_outline() { return outline; }
|
||||
void set_outline(bool p_outline) { outline = p_outline; }
|
||||
|
||||
Point2 get_offset() { return offset; }
|
||||
void set_offset(Point2 p_offset) { offset = p_offset; }
|
||||
|
||||
Color get_color() { return color; }
|
||||
void set_color(Color p_color) { color = p_color; }
|
||||
|
||||
uint32_t get_glyph_index() const { return glyph_index; };
|
||||
void set_glyph_index(uint32_t p_glyph_index) { glyph_index = p_glyph_index; };
|
||||
|
||||
uint16_t get_glyph_flags() const { return glyph_index; };
|
||||
void set_glyph_flags(uint16_t p_glyph_flags) { glyph_flags = p_glyph_flags; };
|
||||
|
||||
uint8_t get_glyph_count() const { return glyph_count; };
|
||||
void set_glyph_count(uint8_t p_glyph_count) { glyph_count = p_glyph_count; };
|
||||
|
||||
RID get_font() const { return font; };
|
||||
void set_font(RID p_font) { font = p_font; };
|
||||
|
||||
|
|
|
@ -852,6 +852,21 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
|||
Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
|
||||
RID frid = glyphs[i].font_rid;
|
||||
uint32_t gl = glyphs[i].index;
|
||||
uint16_t gl_fl = glyphs[i].flags;
|
||||
uint8_t gl_cn = glyphs[i].count;
|
||||
bool cprev = false;
|
||||
if (gl_cn == 0) { // Parts of the same cluster, always connected.
|
||||
cprev = true;
|
||||
}
|
||||
if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
|
||||
if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
|
||||
cprev = true;
|
||||
}
|
||||
} else {
|
||||
if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
|
||||
cprev = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Apply fx.
|
||||
float faded_visibility = 1.0f;
|
||||
|
@ -880,6 +895,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
|||
charfx->outline = true;
|
||||
charfx->font = frid;
|
||||
charfx->glyph_index = gl;
|
||||
charfx->glyph_flags = gl_fl;
|
||||
charfx->glyph_count = gl_cn;
|
||||
charfx->offset = fx_offset;
|
||||
charfx->color = font_color;
|
||||
|
||||
|
@ -895,25 +912,34 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
|||
} else if (item_fx->type == ITEM_SHAKE) {
|
||||
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
|
||||
|
||||
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
|
||||
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
|
||||
uint64_t max_rand = 2147483647;
|
||||
double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
|
||||
n_time = (n_time > 1.0) ? 1.0 : n_time;
|
||||
fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
|
||||
if (!cprev) {
|
||||
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
|
||||
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
|
||||
uint64_t max_rand = 2147483647;
|
||||
double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
|
||||
n_time = (n_time > 1.0) ? 1.0 : n_time;
|
||||
item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
|
||||
}
|
||||
fx_offset += item_shake->prev_off;
|
||||
} else if (item_fx->type == ITEM_WAVE) {
|
||||
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
|
||||
|
||||
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
|
||||
fx_offset += Point2(0, 1) * value;
|
||||
if (!cprev) {
|
||||
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_wave->amplitude / 10.0f);
|
||||
item_wave->prev_off = Point2(0, 1) * value;
|
||||
}
|
||||
fx_offset += item_wave->prev_off;
|
||||
} else if (item_fx->type == ITEM_TORNADO) {
|
||||
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
|
||||
|
||||
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
|
||||
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
|
||||
fx_offset += Point2(torn_x, torn_y);
|
||||
if (!cprev) {
|
||||
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
|
||||
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + gloff.x) / 50)) * (item_tornado->radius);
|
||||
item_tornado->prev_off = Point2(torn_x, torn_y);
|
||||
}
|
||||
fx_offset += item_tornado->prev_off;
|
||||
} else if (item_fx->type == ITEM_RAINBOW) {
|
||||
ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
|
||||
|
||||
|
@ -1004,6 +1030,21 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
|||
Point2 fx_offset = Vector2(glyphs[i].x_off, glyphs[i].y_off);
|
||||
RID frid = glyphs[i].font_rid;
|
||||
uint32_t gl = glyphs[i].index;
|
||||
uint16_t gl_fl = glyphs[i].flags;
|
||||
uint8_t gl_cn = glyphs[i].count;
|
||||
bool cprev = false;
|
||||
if (gl_cn == 0) { // Parts of the same grapheme cluster, always connected.
|
||||
cprev = true;
|
||||
}
|
||||
if (gl_fl & TextServer::GRAPHEME_IS_RTL) { // Check if previous grapheme cluster is connected.
|
||||
if (i > 0 && (glyphs[i - 1].flags & TextServer::GRAPHEME_IS_CONNECTED)) {
|
||||
cprev = true;
|
||||
}
|
||||
} else {
|
||||
if (glyphs[i].flags & TextServer::GRAPHEME_IS_CONNECTED) {
|
||||
cprev = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Apply fx.
|
||||
float faded_visibility = 1.0f;
|
||||
|
@ -1032,6 +1073,8 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
|||
charfx->outline = false;
|
||||
charfx->font = frid;
|
||||
charfx->glyph_index = gl;
|
||||
charfx->glyph_flags = gl_fl;
|
||||
charfx->glyph_count = gl_cn;
|
||||
charfx->offset = fx_offset;
|
||||
charfx->color = font_color;
|
||||
|
||||
|
@ -1047,25 +1090,34 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
|
|||
} else if (item_fx->type == ITEM_SHAKE) {
|
||||
ItemShake *item_shake = static_cast<ItemShake *>(item_fx);
|
||||
|
||||
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
|
||||
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
|
||||
uint64_t max_rand = 2147483647;
|
||||
double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
|
||||
n_time = (n_time > 1.0) ? 1.0 : n_time;
|
||||
fx_offset += Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
|
||||
if (!cprev) {
|
||||
uint64_t char_current_rand = item_shake->offset_random(glyphs[i].start);
|
||||
uint64_t char_previous_rand = item_shake->offset_previous_random(glyphs[i].start);
|
||||
uint64_t max_rand = 2147483647;
|
||||
double current_offset = Math::range_lerp(char_current_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double previous_offset = Math::range_lerp(char_previous_rand % max_rand, 0, max_rand, 0.0f, 2.f * (float)Math_PI);
|
||||
double n_time = (double)(item_shake->elapsed_time / (0.5f / item_shake->rate));
|
||||
n_time = (n_time > 1.0) ? 1.0 : n_time;
|
||||
item_shake->prev_off = Point2(Math::lerp(Math::sin(previous_offset), Math::sin(current_offset), n_time), Math::lerp(Math::cos(previous_offset), Math::cos(current_offset), n_time)) * (float)item_shake->strength / 10.0f;
|
||||
}
|
||||
fx_offset += item_shake->prev_off;
|
||||
} else if (item_fx->type == ITEM_WAVE) {
|
||||
ItemWave *item_wave = static_cast<ItemWave *>(item_fx);
|
||||
|
||||
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
|
||||
fx_offset += Point2(0, 1) * value;
|
||||
if (!cprev) {
|
||||
double value = Math::sin(item_wave->frequency * item_wave->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_wave->amplitude / 10.0f);
|
||||
item_wave->prev_off = Point2(0, 1) * value;
|
||||
}
|
||||
fx_offset += item_wave->prev_off;
|
||||
} else if (item_fx->type == ITEM_TORNADO) {
|
||||
ItemTornado *item_tornado = static_cast<ItemTornado *>(item_fx);
|
||||
|
||||
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
|
||||
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
|
||||
fx_offset += Point2(torn_x, torn_y);
|
||||
if (!cprev) {
|
||||
double torn_x = Math::sin(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
|
||||
double torn_y = Math::cos(item_tornado->frequency * item_tornado->elapsed_time + ((p_ofs.x + off.x) / 50)) * (item_tornado->radius);
|
||||
item_tornado->prev_off = Point2(torn_x, torn_y);
|
||||
}
|
||||
fx_offset += item_tornado->prev_off;
|
||||
} else if (item_fx->type == ITEM_RAINBOW) {
|
||||
ItemRainbow *item_rainbow = static_cast<ItemRainbow *>(item_fx);
|
||||
|
||||
|
|
|
@ -267,6 +267,7 @@ private:
|
|||
float rate = 0.0f;
|
||||
uint64_t _current_rng = 0;
|
||||
uint64_t _previous_rng = 0;
|
||||
Vector2 prev_off;
|
||||
|
||||
ItemShake() { type = ITEM_SHAKE; }
|
||||
|
||||
|
@ -289,6 +290,7 @@ private:
|
|||
struct ItemWave : public ItemFX {
|
||||
float frequency = 1.0f;
|
||||
float amplitude = 1.0f;
|
||||
Vector2 prev_off;
|
||||
|
||||
ItemWave() { type = ITEM_WAVE; }
|
||||
};
|
||||
|
@ -296,6 +298,7 @@ private:
|
|||
struct ItemTornado : public ItemFX {
|
||||
float radius = 1.0f;
|
||||
float frequency = 1.0f;
|
||||
Vector2 prev_off;
|
||||
|
||||
ItemTornado() { type = ITEM_TORNADO; }
|
||||
};
|
||||
|
|
|
@ -447,6 +447,8 @@ void TextServer::_bind_methods() {
|
|||
BIND_ENUM_CONSTANT(GRAPHEME_IS_TAB);
|
||||
BIND_ENUM_CONSTANT(GRAPHEME_IS_ELONGATION);
|
||||
BIND_ENUM_CONSTANT(GRAPHEME_IS_PUNCTUATION);
|
||||
BIND_ENUM_CONSTANT(GRAPHEME_IS_UNDERSCORE);
|
||||
BIND_ENUM_CONSTANT(GRAPHEME_IS_CONNECTED);
|
||||
|
||||
/* Hinting */
|
||||
BIND_ENUM_CONSTANT(HINTING_NONE);
|
||||
|
|
|
@ -91,6 +91,7 @@ public:
|
|||
GRAPHEME_IS_ELONGATION = 1 << 7, // Elongation (e.g. kashida), glyph can be duplicated or truncated to fit line to width.
|
||||
GRAPHEME_IS_PUNCTUATION = 1 << 8, // Punctuation, except underscore (can be used as word break, but not line break or justifiction).
|
||||
GRAPHEME_IS_UNDERSCORE = 1 << 9, // Underscore (can be used as word break).
|
||||
GRAPHEME_IS_CONNECTED = 1 << 10, // Connected to previous grapheme.
|
||||
};
|
||||
|
||||
enum Hinting {
|
||||
|
|
Loading…
Reference in a new issue