[Bf-blender-cvs] [312af01fb4f] blender2.8: 3D Text: improvements to vertical alignment

Dalai Felinto noreply at git.blender.org
Wed Sep 5 03:24:32 CEST 2018


Commit: 312af01fb4faa7d1ff0dea4d2ef936caa9af4c67
Author: Dalai Felinto
Date:   Wed Sep 5 11:21:12 2018 +1000
Branches: blender2.8
https://developer.blender.org/rB312af01fb4faa7d1ff0dea4d2ef936caa9af4c67

3D Text: improvements to vertical alignment

They way Blender handles vertical alignment is very buggy:

- Top-Base: It works perfectly.

- Bottom: It is actually bottom-baseline,
  and it fails when line size is != 1.0 when working with text boxes.

- Top: Poorly implemented, it should use font's ascent
  (recommended distance from baseline),
  so it has room for accents,
  but it's not one line distance far from the origin (as it is now).

- Center: Poorly implemented.
  This is tricky since there is no silver bullet.

To clear this situation I created a new option (Bottom-Baseline),
and addressed the issues above.
I'm getting the ascent and descent from freetype2,
and use this for padding above/below the text.
Also for vertically centering the text.

===================================================================

M	release/scripts/startup/bl_ui/properties_data_curve.py
M	source/blender/blenkernel/intern/font.c
M	source/blender/blenlib/BLI_vfontdata.h
M	source/blender/blenlib/intern/freetypefont.c
M	source/blender/makesdna/DNA_curve_types.h
M	source/blender/makesrna/intern/rna_curve.c

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py
index 671cff4ebb4..9ba6bc70892 100644
--- a/release/scripts/startup/bl_ui/properties_data_curve.py
+++ b/release/scripts/startup/bl_ui/properties_data_curve.py
@@ -398,12 +398,13 @@ class DATA_PT_paragraph_alignment(CurveButtonsPanelText, Panel):
 
     def draw(self, context):
         layout = self.layout
-        layout.use_property_split = False
+        layout.use_property_split = True
 
         text = context.curve
 
-        layout.row().prop(text, "align_x", expand=True)
-        layout.row().prop(text, "align_y", expand=True)
+        col = layout.column()
+        col.prop(text, "align_x", text="Horizontal")
+        col.prop(text, "align_y", text="Vertical")
 
 
 class DATA_PT_paragraph_spacing(CurveButtonsPanelText, Panel):
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index b5fba6d30e8..31de8d8d51e 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -635,6 +635,22 @@ struct TempLineInfo {
 	int   wspace_nr;  /* number of whitespaces of line */
 };
 
+/**
+ * Font metric values explained:
+ *
+ * Baseline: Line where the text "rests", used as the origin vertical position for the glyphs.
+ * Em height: Space most glyphs should fit within.
+ * Ascent: the recommended distance above the baseline to fit most characters.
+ * Descent: the recommended distance below the baseline to fit most characters.
+ *
+ * We obtain ascent and descent from the font itself (FT_Face->ascender / face->height).
+ * And in some cases it is even the same value as FT_Face->bbox.yMax/yMin (font top and bottom respectively).
+ *
+ * The em_height here is relative to FT_Face->bbox.
+*/
+#define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height)
+#define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd))
+
 bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
                            const wchar_t **r_text, int *r_text_len, bool *r_text_free,
                            struct CharTrans **r_chartransdata)
@@ -1019,26 +1035,30 @@ makebreak:
 	/* top-baseline is default, in this case, do nothing */
 	if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
 		if (tb_scale.h != 0.0f) {
-			/* top and top-baseline are the same when text-boxes are used */
-			if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
-				/* all previous textboxes are 'full', only align the last used text-box */
+			if (i_textbox < slen) {
+				/* All previous textboxes are 'full', only align the last used text-box. */
+				struct CharTrans *ct_textbox = chartransdata + i_textbox;
 				float yoff = 0.0f;
-				int lines;
-				struct CharTrans *ct_last, *ct_textbox;
 
-				ct_last = chartransdata + slen - 1;
-				ct_textbox = chartransdata + i_textbox;
+				/* The initial Y origin of the textbox is harcoded to 1.0f * text scale. */
+				const float textbox_y_origin = 1.0f;
 
-				lines = ct_last->linenr - ct_textbox->linenr + 1;
-				if (mem[slen - 1] == '\n') {
-					lines++;
-				}
-
-				if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
-					yoff = (lines * linedist) - tb_scale.h;
-				}
-				else if (cu->align_y == CU_ALIGN_Y_CENTER) {
-					yoff = 0.5f * ((lines * linedist) - tb_scale.h);
+				switch (cu->align_y) {
+					case CU_ALIGN_Y_TOP_BASELINE:
+						break;
+					case CU_ALIGN_Y_TOP:
+						yoff = textbox_y_origin - ASCENT(vfd);
+						break;
+					case CU_ALIGN_Y_CENTER:
+						yoff = ((((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd)) -
+						        (tb_scale.h  * 0.5f) + textbox_y_origin);
+						break;
+					case CU_ALIGN_Y_BOTTOM_BASELINE:
+						yoff = textbox_y_origin + ((lnr - 1) * linedist) - tb_scale.h;
+						break;
+					case CU_ALIGN_Y_BOTTOM:
+						yoff = textbox_y_origin + ((lnr - 1) * linedist) - tb_scale.h + DESCENT(vfd);
+						break;
 				}
 
 				ct = ct_textbox;
@@ -1049,18 +1069,25 @@ makebreak:
 			}
 		}
 		else {
-			/* non text-box case handled separately */
+			/* Non text-box case handled separately. */
 			ct = chartransdata;
 			float yoff = 0.0f;
 
-			if (cu->align_y == CU_ALIGN_Y_TOP) {
-				yoff = -linedist;
-			}
-			else if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
-				yoff = (lnr - 1.0f) * linedist;
-			}
-			else if (cu->align_y == CU_ALIGN_Y_CENTER) {
-				yoff = (lnr - 2.0f) * linedist * 0.5f;
+			switch (cu->align_y) {
+				case CU_ALIGN_Y_TOP_BASELINE:
+					break;
+				case CU_ALIGN_Y_TOP:
+					yoff = -ASCENT(vfd);
+					break;
+				case CU_ALIGN_Y_CENTER:
+					yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd);
+					break;
+				case CU_ALIGN_Y_BOTTOM_BASELINE:
+					yoff = (lnr - 1) * linedist;
+					break;
+				case CU_ALIGN_Y_BOTTOM:
+					yoff = (lnr - 1) * linedist + DESCENT(vfd);
+					break;
 			}
 
 			for (i = 0; i <= slen; i++) {
@@ -1339,6 +1366,8 @@ finally:
 #undef MARGIN_Y_MIN
 }
 
+#undef DESCENT
+#undef ASCENT
 
 bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase)
 {
diff --git a/source/blender/blenlib/BLI_vfontdata.h b/source/blender/blenlib/BLI_vfontdata.h
index 1cc1ef17486..892d084f5ee 100644
--- a/source/blender/blenlib/BLI_vfontdata.h
+++ b/source/blender/blenlib/BLI_vfontdata.h
@@ -43,6 +43,9 @@ typedef struct VFontData {
 	struct GHash *characters;
 	char name[128];
 	float scale;
+	/* Calculated from the font. */
+	float em_height;
+	float ascender;
 } VFontData;
 
 typedef struct VChar {
diff --git a/source/blender/blenlib/intern/freetypefont.c b/source/blender/blenlib/intern/freetypefont.c
index c7604b3cd6d..3f3868bea45 100644
--- a/source/blender/blenlib/intern/freetypefont.c
+++ b/source/blender/blenlib/intern/freetypefont.c
@@ -359,10 +359,27 @@ static VFontData *objfnt_to_ftvfontdata(PackedFile *pf)
 		lcode = charcode = FT_Get_First_Char(face, &glyph_index);
 	}
 
+	/* Blender default BFont is not "complete". */
+	const bool complete_font = (face->ascender != 0) && (face->descender != 0) &&
+	                           (face->ascender != face->descender);
+
+	if (complete_font) {
+		/* We can get descender as well, but we simple store descender in relation to the ascender.
+		 * Also note that descender is stored as a negative number. */
+		vfd->ascender = (float)face->ascender / (face->ascender - face->descender);
+	}
+	else {
+		vfd->ascender = 0.8f;
+		vfd->em_height = 1.0f;
+	}
 
 	/* Adjust font size */
 	if (face->bbox.yMax != face->bbox.yMin) {
 		vfd->scale = (float)(1.0 / (double)(face->bbox.yMax - face->bbox.yMin));
+
+		if (complete_font) {
+			vfd->em_height = (float)(face->ascender - face->descender) / (face->bbox.yMax - face->bbox.yMin);
+		}
 	}
 	else {
 		vfd->scale = 1.0f / 1000.0f;
diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h
index 6e3573b9f80..7c7eaae4949 100644
--- a/source/blender/makesdna/DNA_curve_types.h
+++ b/source/blender/makesdna/DNA_curve_types.h
@@ -334,7 +334,8 @@ enum {
 	CU_ALIGN_Y_TOP_BASELINE       = 0,
 	CU_ALIGN_Y_TOP                = 1,
 	CU_ALIGN_Y_CENTER             = 2,
-	CU_ALIGN_Y_BOTTOM             = 3,
+	CU_ALIGN_Y_BOTTOM_BASELINE    = 3,
+	CU_ALIGN_Y_BOTTOM             = 4,
 };
 
 /* Nurb.flag */
diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c
index 6b294b9b3cd..a90a5cdff90 100644
--- a/source/blender/makesrna/intern/rna_curve.c
+++ b/source/blender/makesrna/intern/rna_curve.c
@@ -969,6 +969,8 @@ static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna)
 		{CU_ALIGN_Y_TOP, "TOP", 0, "Top", "Align text to the top"},
 		{CU_ALIGN_Y_CENTER, "CENTER", 0, "Center", "Align text to the middle"},
 		{CU_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", "Align text to the bottom"},
+		{CU_ALIGN_Y_BOTTOM_BASELINE, "BOTTOM_BASELINE", 0, "Bottom Base-Line",
+		"Align text to the bottom but use the base-line of the text"},
 		{0, NULL, 0, NULL, NULL}
 	};



More information about the Bf-blender-cvs mailing list