Skip to content

tinne26/etxt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

etxt

Go Reference

etxt is a package for vectorial1 text rendering in Golang designed to be used with Ebitengine, the 2D game engine made by Hajime Hoshi.

While Ebitengine already includes the ebiten/v2/text/v2 package, etxt has some advantages over it:

  • Makes text size easy to change.
  • Puts emphasis on getting display scaling right.
  • Gets rid of font.Face for good.
  • Provides high quality documentation and examples.
  • Helps out with some extras like faux bold, faux oblique, basic line wrapping, embedded fonts, glyph quantization, line spacing, etc.
  • Exposes caches, rasterizers and sizers for you to adapt if you have more advanced needs.

What etxt doesn't do:

  • No general text layout. Features like bidi, itemization, shaping, general hit testing, justification and others are not covered and in most cases aren't a primary goal for this package.
  • Poor or no support for complex scripts (e.g. Arabic) nor vertical text layouts (e.g. Japanese). Notice that ebiten/v2/text/v2 fares much better in this regard.
  • None of the things people actually want: shadows and outlines, gamma correction, subpixel antialiasing, Knuth-Plass line breaking, better support for shaders, etc. Some can already be crudely faked, some will be added in the future... but this is the situation right now.

If you are unfamiliar with typography terms and concepts, I highly recommend reading the first chapters of FreeType Glyph Conventions; one the best references on the topic you can find on the internet.

Code example

Less talk and more code!

package main

import ( "math" ; "image/color" )
import "github.com/hajimehoshi/ebiten/v2"
import "github.com/tinne26/etxt"
import "github.com/tinne26/fonts/liberation/lbrtserif"

const WordsPerSec = 2.71828
var Words = []string {
	"solitude", "joy", "ride", "whisper", "leaves", "cookie",
	"hearts", "disdain", "simple", "death", "sea", "shallow",
	"self", "rhyme", "childish", "sky", "tic", "tac", "boom",
}

// ---- Ebitengine's Game interface implementation ----

type Game struct { text *etxt.Renderer ; wordIndex float64 }

func (self *Game) Layout(winWidth int, winHeight int) (int, int) {
	scale := ebiten.DeviceScaleFactor() // *
	// * ebiten.Monitor().DeviceScaleFactor() in >=v2.7.0
	self.text.SetScale(scale) // relevant for HiDPI
	canvasWidth  := int(math.Ceil(float64(winWidth)*scale))
	canvasHeight := int(math.Ceil(float64(winHeight)*scale))
	return canvasWidth, canvasHeight
}

func (self *Game) Update() error {
	newIndex := (self.wordIndex + WordsPerSec/60.0)
	self.wordIndex = math.Mod(newIndex, float64(len(Words)))
	return nil
}

func (self *Game) Draw(canvas *ebiten.Image) {
	// background color
	canvas.Fill(color.RGBA{229, 255, 222, 255})
	
	// get screen center position
	bounds := canvas.Bounds() // assumes origin (0, 0)
	x, y := bounds.Dx()/2, bounds.Dy()/2

	// draw text
	word := Words[int(self.wordIndex)]
	self.text.Draw(canvas, word, x, y)
}

// ---- main function ----

func main() {
	// create text renderer, set the font and cache
	renderer := etxt.NewRenderer()
	renderer.SetFont(lbrtserif.Font())
	renderer.Utils().SetCache8MiB()
	
	// adjust main text style properties
	renderer.SetColor(color.RGBA{239, 91, 91, 255})
	renderer.SetAlign(etxt.Center)
	renderer.SetSize(72)

	// set up Ebitengine and start the game
	ebiten.SetWindowTitle("etxt/examples/ebiten/words")
	err := ebiten.RunGame(&Game{ text: renderer })
	if err != nil { panic(err) }
}

You can try running this yourself with2:

go run github.com/tinne26/etxt/examples/ebiten/words@latest

Alternatively, you can go to https://tinne26.github.io/etxt-examples/ and click on the first example for the web version.

This is a very simple and self-contained example. If you want to learn more, make sure to take a look at etxt/examples!

Can I use this package without Ebitengine?

Yeah, you can compile it with -tags gtxt. Notice that gtxt will make text drawing happen on the CPU, so don't try to use it for real-time applications. In particular, be careful to not accidentally use gtxt with Ebitengine (they are compatible in many cases, but performance will die).

Testing, contributions and others

  • For testing, see the instructions on etxt/test.
  • If you have any questions or suggestions for improvements feel free to speak, I'm always happy to explain or discuss.
  • Otherwise, I'm not looking for contributors nor general help.

Footnotes

  1. If you are using pixel-art-like vectorial fonts, read these tips.

  2. You will need Golang >=1.18, and if you have never used Ebitengine before, you may need to install some dependencies (typically only on Linux or FreeBSD).