Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose dynamic font vector outlines to the GDScript. #44289

Merged
merged 1 commit into from
Mar 31, 2021

Conversation

bruvzg
Copy link
Member

@bruvzg bruvzg commented Dec 11, 2020

Exposes vector outlines to the scripts, might be useful for generating 3D meshes from the shaped text and other complex text effects.

Test code:

extends Control

var rid
var trid
var gl
var data = []

func _ready():
	# Load font and shape text
	rid = TextServerManager.get_primary_interface().create_font_resource("res://ComicNeue-Bold.otf", 72)
	trid = TextServerManager.get_primary_interface().create_shaped_text()
	TextServerManager.get_primary_interface().shaped_text_add_string(trid, "Abc", [rid], 72);
	gl = TextServerManager.get_primary_interface().shaped_text_get_glyphs(trid);
	# Get glyph outlines
	for g in gl:
		data.push_back(TextServerManager.get_primary_interface().font_get_glyph_contours(g.get("font_rid"), g.get("font_size"), g.get("index")))

func _exit_tree():
	# Unload text buffer and font
	TextServerManager.get_primary_interface().free_rid(rid)
	TextServerManager.get_primary_interface().free_rid(trid)

func draw_conic(p0, p1, p2, color):
	var prev = Vector2()
	var t = 0.0
	while(t <= 1.0):
		var omt = (1.0 - t)
		var omt2 = omt * omt
		var t2 = t * t
		
		var point = p1 + omt2 * (p0 - p1) + t2 * (p2 - p1)
		if prev != Vector2():
			draw_line(prev, point, color)
		prev = point
		t += 0.1

func draw_cubic(p0, p1, p2, p3, color):
	var prev = Vector2()
	var t = 0.0
	while(t <= 1.0):
		var omt = (1.0 - t)
		var omt2 = omt * omt
		var omt3 = omt2 * omt
		var t2 = t * t
		var t3 = t2 * t

		var point = p0 * omt3 + p1 * omt2 * t * 3.0 + p2 * omt * t2 * 3.0 + p3 * t3
		if prev != Vector2():
			draw_line(prev, point, color)
		prev = point
		t += 0.1

func _draw():
	var origin = Vector2(100, 100)
	var idx = 0
	for g in gl:
		var off = origin + g.get("offset") * 10
		var points = data[idx].get("points")
		var contours = data[idx].get("contours")

		# Draw glyph outline
		var point = 0
		for cnt in contours:
			var prev
			if points[cnt].z == TextServer.CONTOUR_CURVE_TAG_ON:
				prev = Vector2(points[cnt].x, points[cnt].y) * 10 + off
			else:
				prev = Vector2(points[point].x, points[point].y) * 10 + off
			var first = point
			while(point <= cnt):
				var p = points[point]
				if p.z == TextServer.CONTOUR_CURVE_TAG_ON:
					# Line segment
					draw_string(get_theme_font("font"), Vector2(p.x + 1, p.y + 1) * 10 + off, str(point))
					draw_circle(Vector2(p.x, p.y) * 10 + off, 5, Color(1,0,0))
					draw_line(prev, Vector2(p.x, p.y) * 10 + off, Color(0,0,1))
					prev = Vector2(p.x, p.y) * 10 + off
					point += 1
					continue

				if p.z == TextServer.CONTOUR_CURVE_TAG_OFF_CONIC:
					# Quadratic Bézier segment
					var p1
					if point == cnt:
						p1 = points[first]
					else:
						p1 = points[point + 1]
						draw_string(get_theme_font("font"), Vector2(p1.x + 1, p1.y + 1) * 10 + off, str(point + 1))
					draw_string(get_theme_font("font"), Vector2(p.x + 1, p.y + 1) * 10 + off, str(point))
					draw_conic(prev, Vector2(p.x, p.y) * 10 + off, Vector2(p1.x, p1.y) * 10 + off, Color(0,0,1))
					draw_arc(Vector2(p.x, p.y) * 10 + off, 5, 0, 3 * PI, 20, Color(1,0,0))
					draw_circle(Vector2(p1.x, p1.y) * 10 + off, 5, Color(1,0,0))
					prev = Vector2(p1.x, p1.y) * 10 + off
					point += 2
					continue

				if p.z == TextServer.CONTOUR_CURVE_TAG_OFF_CUBIC:
					# Cubic Bézier segment
					var p1
					var p2
					if point == cnt:
						p1 = points[first]
						p2 = points[first + 1]
					elif point == cnt - 1:
						p1 = points[point + 1]
						p2 = points[first]
						draw_string(get_theme_font("font"), Vector2(p1.x + 1, p1.y + 1) * 10 + off, str(point + 1))
					else:
						p1 = points[point + 1]
						p2 = points[point + 2]
						draw_string(get_theme_font("font"), Vector2(p1.x + 1, p1.y + 1) * 10 + off, str(point + 1))
						draw_string(get_theme_font("font"), Vector2(p2.x + 1, p2.y + 1) * 10 + off, str(point + 2))
					draw_string(get_theme_font("font"), Vector2(p.x + 1, p.y + 1) * 10 + off, str(point))
					draw_cubic(prev, Vector2(p.x, p.y) * 10 + off, Vector2(p1.x, p1.y) * 10 + off, Vector2(p2.x, p2.y) * 10 + off, Color(0,0,1))
					draw_arc(Vector2(p.x, p.y) * 10 + off, 5, 0, 3 * PI, 20, Color(1,0,0))
					draw_arc(Vector2(p1.x, p1.y) * 10 + off, 5, 0, 3 * PI, 20, Color(1,0,0))
					draw_circle(Vector2(p2.x, p2.y) * 10 + off, 5, Color(1,0,0))
					prev = Vector2(p2.x, p2.y) * 10 + off
					point += 3
					continue
			point = cnt + 1
		origin.x += g.get("advance") * 10
		idx += 1

func _process(delta):
	update()

outline2

@bruvzg bruvzg added this to the 4.0 milestone Dec 11, 2020
@bruvzg bruvzg force-pushed the ctl_gl_contours branch 2 times, most recently from f33070f to 0d79afd Compare December 11, 2020 12:44
@bruvzg bruvzg changed the title [WIP] Expose dynamic font vector outlines to the GDScript. Expose dynamic font vector outlines to the GDScript. Dec 11, 2020
@bruvzg bruvzg marked this pull request as ready for review December 11, 2020 12:48
@bruvzg bruvzg requested a review from a team as a code owner December 11, 2020 12:48
@bruvzg bruvzg force-pushed the ctl_gl_contours branch 4 times, most recently from 4be42d2 to 913a2a8 Compare December 13, 2020 19:08
Copy link
Member

@Calinou Calinou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The feature looks good to me, although I can't see too many use cases for it personally. Maybe this is more useful with icon fonts, but icon fonts are generally considered to be on the way out (with SVG being favored for web icons nowadays).

Also, the documentation should be made more complete.

doc/classes/TextServer.xml Outdated Show resolved Hide resolved
@bruvzg bruvzg requested review from a team as code owners March 31, 2021 06:37
@akien-mga akien-mga merged commit 3096423 into godotengine:master Mar 31, 2021
@bruvzg bruvzg deleted the ctl_gl_contours branch March 31, 2021 07:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants