Refactoring: Corrections and unifications in mathematics vfont gizmos #107193

Closed
Iliya Katushenock wants to merge 19 commits from mod_moder/blender:tmp_fix_text_cursor_transform into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
6 changed files with 138 additions and 101 deletions

View File

@ -23,10 +23,14 @@ struct CharTrans {
char dobreak;
};
typedef struct EditFontSelBox {
float x, y, w, h;
/**
* Extra gizmo transform for symbol.
* */
typedef struct EditFontCharExtra {
float loc[2];
float size[2];
float rot;
} EditFontSelBox;
} EditFontCharExtra;
/**
* Edit data for #Curve (a text curve, with an #Object::type of `OB_FONT`).
@ -37,9 +41,8 @@ typedef struct EditFont {
/** Text style info (aligned with `textbuf`). */
struct CharInfo *textbufinfo;
/** Array of rectangles & rotation. */
float textcurs[4][2];
EditFontSelBox *selboxes;
EditFontCharExtra cursor;
EditFontCharExtra *selboxes;
int selboxes_len;
/* Positional vars relative to the `textbuf` (not utf8 bytes)

View File

@ -801,7 +801,7 @@ static bool vfont_to_curve(Object *ob,
struct CharTrans **r_chartransdata)
{
EditFont *ef = cu->editfont;
EditFontSelBox *selboxes = NULL;
EditFontCharExtra *selboxes = NULL;
VFont *vfont, *oldvfont;
VFontData *vfd = NULL;
CharInfo *info = NULL, *custrinfo;
@ -810,7 +810,7 @@ static bool vfont_to_curve(Object *ob,
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
struct TempLineInfo *lineinfo;
float *f, xof, yof, xtrax, linedist;
float xof, yof, xtrax, linedist;
float twidth = 0, maxlen = 0;
int i, slen, j;
int curbox;
@ -897,7 +897,8 @@ static bool vfont_to_curve(Object *ob,
if (BKE_vfont_select_get(ob, &selstart, &selend)) {
ef->selboxes_len = (selend - selstart) + 1;
ef->selboxes = MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes");
ef->selboxes = MEM_calloc_arrayN(
ef->selboxes_len, sizeof(EditFontCharExtra), "font selboxes");
}
else {
ef->selboxes_len = 0;
@ -1112,7 +1113,7 @@ static bool vfont_to_curve(Object *ob,
xof = MARGIN_X_MIN + tabfac;
}
else {
EditFontSelBox *sb = NULL;
EditFontCharExtra *sb = NULL;
float wsfac;
ct->xof = xof;
@ -1122,9 +1123,9 @@ static bool vfont_to_curve(Object *ob,
if (selboxes && (i >= selstart) && (i <= selend)) {
sb = &selboxes[i - selstart];
sb->y = yof * font_size - linedist * font_size * 0.1f;
sb->h = linedist * font_size;
sb->w = xof * font_size;
sb->loc[1] = yof * font_size - linedist * font_size * 0.1f;
sb->size[0] = xof * font_size;
sb->size[1] = linedist * font_size;
}
if (ascii == ' ') { /* Space character. */
@ -1141,7 +1142,7 @@ static bool vfont_to_curve(Object *ob,
xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f))) + xtrax;
if (sb) {
sb->w = (xof * font_size) - sb->w;
sb->size[0] = (xof * font_size) - sb->size[0];
}
}
ct++;
@ -1442,22 +1443,30 @@ static bool vfont_to_curve(Object *ob,
ct->yof = vec[1] + co * yof;
if (selboxes && (i >= selstart) && (i <= selend)) {
EditFontSelBox *sb;
sb = &selboxes[i - selstart];
EditFontCharExtra *sb = &selboxes[i - selstart];
sb->rot = -ct->rot;
}
}
}
}
const float descender_downship = 0.25f;
if (selboxes) {
ct = chartransdata;
for (i = 0; i <= selend; i++, ct++) {
if (i >= selstart) {
selboxes[i - selstart].x = ct->xof * font_size;
selboxes[i - selstart].y = (ct->yof - 0.25f) * font_size;
selboxes[i - selstart].h = font_size;
}
ct += selstart;
for (i = 0; i < ef->selboxes_len; i++, ct++) {
selboxes[i].size[1] = font_size;
float centre_offset[2];
copy_v2_v2(centre_offset, selboxes[i].size);
mul_v2_fl(centre_offset, 1.0f / font_size);
mul_v2_fl(centre_offset, 0.5f);
centre_offset[1] -= descender_downship;
rotate_v2_v2fl(selboxes[i].loc, centre_offset, selboxes[i].rot);
add_v2_v2(selboxes[i].loc, &ct->xof);
mul_v2_fl(selboxes[i].loc, font_size);
}
}
@ -1534,27 +1543,75 @@ static bool vfont_to_curve(Object *ob,
}
}
/* Cursor first. */
/* Cursor transform. */
if (ef) {
float si, co;
const int cursor_index = ef->pos;
const int prev_index = cursor_index != 0 ? cursor_index - 1 : cursor_index;
ct = &chartransdata[ef->pos];
si = sinf(ct->rot);
co = cosf(ct->rot);
const bool is_line_cap = ELEM(cursor_index, 0, slen) || ELEM(mem[cursor_index], '\n', '\0') ||
ELEM(mem[cursor_index - 1], '\n', '\0');
const bool is_start_cap = (cursor_index == 0) || ELEM(mem[cursor_index - 1], '\n', '\0');
f = ef->textcurs[0];
const bool is_word_space = !is_line_cap && (mem[prev_index] != ' ') &&
(mem[cursor_index] == ' ');
const bool is_space_word = !is_line_cap && (mem[prev_index] == ' ') &&
(mem[cursor_index] != ' ');
f[0] = font_size * (-0.02f * co + ct->xof);
f[1] = font_size * (0.1f * si - (0.25f * co) + ct->yof);
const bool is_between_space_and_word = is_word_space || is_space_word;
f[2] = font_size * (0.02f * co + ct->xof);
f[3] = font_size * (-0.1f * si - (0.25f * co) + ct->yof);
/* After or before of selections. Cursor alway related with selection if is exist. */
const bool cursor_to_selection = selboxes != NULL;
const bool is_before_selection = cursor_index == selstart;
f[4] = font_size * (0.02f * co + 0.8f * si + ct->xof);
f[5] = font_size * (-0.1f * si + 0.75f * co + ct->yof);
const float curent_char_rot = -chartransdata[cursor_index].rot;
const float prev_char_rot = -chartransdata[prev_index].rot;
f[6] = font_size * (-0.02f * co + 0.8f * si + ct->xof);
f[7] = font_size * (0.1f * si + 0.75f * co + ct->yof);
float current_char_loc[2];
copy_v2_v2(current_char_loc, &chartransdata[cursor_index].xof);
float prev_char_loc[2];
copy_v2_v2(prev_char_loc, &chartransdata[prev_index].xof);
if (cursor_index != prev_index) {
che = find_vfont_char(vfd, mem[prev_index]);
info = &custrinfo[prev_index];
float prev_offset[2];
zero_v2(prev_offset);
prev_offset[0] = char_width(cu, che, info);
float tmp_rotated[2];
rotate_v2_v2fl(tmp_rotated, prev_offset, prev_char_rot);
add_v2_v2(prev_char_loc, tmp_rotated);
}
float cursor_loc[2];
float cursor_centre[2] = {0.0f, 0.5f};
cursor_centre[1] -= descender_downship;
float cursor_rot = 0.0f;
/* Default alignment is between previous and current symbol. */
float align_factor = 0.5f;
if (is_line_cap) {
/* Align to start or end of each line. */
align_factor = is_start_cap ? 1.0f : 0.0f;
}
else if (cursor_to_selection) {
align_factor = is_before_selection ? 1.0f : 0.0f;
}
else if (is_between_space_and_word) {
/* Align to text, if cursor between regular text and space. */
align_factor = is_space_word ? 1.0f : 0.0f;
}
cursor_rot = slerp_r_r(prev_char_rot, curent_char_rot, align_factor);
interp_v2_v2v2(cursor_loc, prev_char_loc, current_char_loc, align_factor);
rotate_v2_v2fl(ef->cursor.loc, cursor_centre, cursor_rot);
add_v2_v2(ef->cursor.loc, cursor_loc);
mul_v2_fl(ef->cursor.loc, font_size);
ef->cursor.size[0] = 0.05f;
ef->cursor.size[1] = 1.0f;
mul_v2_fl(ef->cursor.size, font_size);
ef->cursor.rot = cursor_rot;
}
if (mode == FO_SELCHANGE) {
@ -1787,16 +1844,8 @@ bool BKE_vfont_to_curve_ex(Object *ob,
};
do {
data.ok &= vfont_to_curve(ob,
cu,
mode,
&data,
NULL,
r_nubase,
r_text,
r_text_len,
r_text_free,
r_chartransdata);
data.ok &= vfont_to_curve(
ob, cu, mode, &data, NULL, r_nubase, r_text, r_text_len, r_text_free, r_chartransdata);
} while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT));
return data.ok;

View File

@ -106,6 +106,7 @@ bool is_zero_qt(const float q[4]);
void interp_dot_slerp(float t, float cosom, float r_w[2]);
void interp_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
void add_qt_qtqt(float q[4], const float a[4], const float b[4], float t);
float slerp_r_r(const float r1, const float r2, const float t);
/* Conversion. */

View File

@ -898,6 +898,20 @@ void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t)
q[3] = a[3] + t * b[3];
}
float slerp_r_r(const float r1, const float r2, const float t)
{
const float r1_s = sinf(r1);
const float r1_c = cosf(r1);
const float r2_s = sinf(r2);
const float r2_c = cosf(r2);
const float m_s = r1_s + (r2_s - r1_s) * t;
const float m_c = r1_c + (r2_c - r1_c) * t;
return atan2f(m_s, m_c);
}
void tri_to_quat_ex(
float quat[4], const float v1[3], const float v2[3], const float v3[3], const float no_orig[3])
{

View File

@ -66,61 +66,30 @@ void OVERLAY_edit_text_cache_init(OVERLAY_Data *vedata)
}
}
/* Use 2D quad corners to create a matrix that set
* a [-1..1] quad at the right position. */
static void v2_quad_corners_to_mat4(const float corners[4][2], float r_mat[4][4])
static void v2_transform_to_mat4(const float loc[2],
const float rot,
const float scale[2],
float r_mat[4][4])
{
unit_m4(r_mat);
sub_v2_v2v2(r_mat[0], corners[1], corners[0]);
sub_v2_v2v2(r_mat[1], corners[3], corners[0]);
mul_v2_fl(r_mat[0], 0.5f);
mul_v2_fl(r_mat[1], 0.5f);
copy_v2_v2(r_mat[3], corners[0]);
add_v2_v2(r_mat[3], r_mat[0]);
add_v2_v2(r_mat[3], r_mat[1]);
const float loc_v3[3] = {loc[0], loc[1], 0.0f};
const float rot_v3[3] = {0.0f, 0.0f, rot};
float size_v3[3] = {scale[0], scale[1], 0.0f};
mul_v3_fl(size_v3, 0.5f);
loc_eul_size_to_mat4(r_mat, loc_v3, rot_v3, size_v3);
}
static void edit_text_cache_populate_select(OVERLAY_Data *vedata, Object *ob)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
const Curve *cu = static_cast<Curve *>(ob->data);
EditFont *ef = cu->editfont;
float final_mat[4][4], box[4][2];
EditFont &edit_font = *cu->editfont;
struct GPUBatch *geom = DRW_cache_quad_get();
for (int i = 0; i < ef->selboxes_len; i++) {
EditFontSelBox *sb = &ef->selboxes[i];
float selboxw;
if (i + 1 != ef->selboxes_len) {
if (ef->selboxes[i + 1].y == sb->y) {
selboxw = ef->selboxes[i + 1].x - sb->x;
}
else {
selboxw = sb->w;
}
}
else {
selboxw = sb->w;
}
/* NOTE: v2_quad_corners_to_mat4 don't need the 3rd corner. */
if (sb->rot == 0.0f) {
copy_v2_fl2(box[0], sb->x, sb->y);
copy_v2_fl2(box[1], sb->x + selboxw, sb->y);
copy_v2_fl2(box[3], sb->x, sb->y + sb->h);
}
else {
float mat[2][2];
angle_to_mat2(mat, sb->rot);
copy_v2_fl2(box[0], sb->x, sb->y);
mul_v2_v2fl(box[1], mat[0], selboxw);
add_v2_v2(box[1], &sb->x);
mul_v2_v2fl(box[3], mat[1], sb->h);
add_v2_v2(box[3], &sb->x);
}
v2_quad_corners_to_mat4(box, final_mat);
float final_mat[4][4];
for (int i = 0; i < edit_font.selboxes_len; i++) {
EditFontCharExtra &sb = edit_font.selboxes[i];
v2_transform_to_mat4(sb.loc, sb.rot, sb.size, final_mat);
mul_m4_m4m4(final_mat, ob->object_to_world, final_mat);
DRW_shgroup_call_obmat(pd->edit_text_selection_grp, geom, final_mat);
}
}
@ -129,11 +98,11 @@ static void edit_text_cache_populate_cursor(OVERLAY_Data *vedata, Object *ob)
{
OVERLAY_PrivateData *pd = vedata->stl->pd;
const Curve *cu = static_cast<Curve *>(ob->data);
EditFont *edit_font = cu->editfont;
float(*cursor)[2] = edit_font->textcurs;
float mat[4][4];
EditFont &edit_font = *cu->editfont;
EditFontCharExtra &cursor = edit_font.cursor;
v2_quad_corners_to_mat4(cursor, mat);
float mat[4][4];
v2_transform_to_mat4(cursor.loc, cursor.rot, cursor.size, mat);
mul_m4_m4m4(mat, ob->object_to_world, mat);
struct GPUBatch *geom = DRW_cache_quad_get();

View File

@ -259,13 +259,14 @@ bool view3d_orbit_calc_center(bContext *C, float r_dyn_ofs[3])
}
else if (ob_act && (ob_act->mode & OB_MODE_EDIT) && (ob_act->type == OB_FONT)) {
Curve *cu = static_cast<Curve *>(ob_act_eval->data);
EditFont *ef = cu->editfont;
EditFont &edit_font = *cu->editfont;
EditFontCharExtra &cursor = edit_font.cursor;
zero_v3(lastofs);
for (int i = 0; i < 4; i++) {
add_v2_v2(lastofs, ef->textcurs[i]);
}
mul_v2_fl(lastofs, 1.0f / 4.0f);
float centre[3];
zero_v3(centre);
centre[1] = cursor.size[1] / 2.0f;
rotate_v2_v2fl(lastofs, centre, cursor.rot);
add_v2_v2(lastofs, cursor.loc);
mul_m4_v3(ob_act_eval->object_to_world, lastofs);