etxt

package module
v0.0.9-alpha.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 4, 2024 License: MIT Imports: 11 Imported by: 72

README

etxt

Go Reference

NOTICE: this is a preview of v0.0.9, which is a non-trivial departure from previous versions. For the latest stable version, see v0.0.8.

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

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

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()
	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 with[^2]:

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.

[^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).

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.

Documentation

Overview

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

To get started, you should create a Renderer and set up a font and a cache:

text := etxt.NewRenderer()
text.SetFont(font) // e.g. lbrtsans.Font() from github.com/tinne26/fonts
text.Utils().SetCache8MiB()

Then, you can further adjust the renderer properties with functions like Renderer.SetColor(), Renderer.SetSize(), Renderer.SetAlign(), Renderer.SetScale() and many others.

Once you have everything configured to your liking, drawing is quite straightforward:

text.Draw(canvas, "Hello world!", x, y)

To learn more, make sure to check the examples!

Index

Constants

View Source
const (
	QtNone = fract.Unit(1)  // full glyph position resolution (1/64ths of a pixel)
	Qt32th = fract.Unit(2)  // quantize glyph positions to 1/32ths of a pixel
	Qt16th = fract.Unit(4)  // quantize glyph positions to 1/16ths of a pixel
	Qt8th  = fract.Unit(8)  // quantize glyph positions to 1/ 8ths of a pixel
	Qt4th  = fract.Unit(16) // quantize glyph positions to 1/ 4ths of a pixel
	QtHalf = fract.Unit(32) // quantize glyph positions to half of a pixel
	QtFull = fract.Unit(64) // full glyph position quantization
)

Quantization levels are used to control the trade-off between memory usage and glyph positioning precision. Less theoretically:

  • A font is a collection of glyph outlines. Each time we want to draw a glyph at a specific size, we need to rasterize its outline into a bitmap. That's expensive, so we want to cache the bitmaps.
  • Now we have some text and we want to start drawing each letter one after another, but... most of the time, the glyph positions won't align to the pixel grid perfectly. Should we force this alignment? Or should we rasterize glyph variants for each subposition?

The answer is that it depends on what we are trying to do. Quantization levels allow us to adjust the number of positional variants we want to consider for each glyph. More variants mean higher memory usage. Less variants mean lower positioning precision.

Quantization levels can be adjusted with RendererFract.SetHorzQuantization() and RendererFract.SetVertQuantization(), though in general they are not something you should be touching unless you know what you are doing.

Only the equispaced quantization values are given. Other values like fract.Unit(22) (which approximates one third of a pixel, ceil(64/3)) could also work in theory, but in practice they lead to implementation complications that are simply not worth it.

Variables

View Source
var (
	OnMissSkip   = func(*sfnt.Font, rune) (sfnt.GlyphIndex, bool) { return 0, true }
	OnMissNotdef = func(*sfnt.Font, rune) (sfnt.GlyphIndex, bool) { return 0, false }
)

Basic handlers for RendererGlyph.SetMissHandler().

Functions

This section is empty.

Types

type Align added in v0.0.9

type Align uint8

Aligns tell a Renderer how to interpret the coordinates that Renderer.Draw() and other operations receive.

More concretely: given some text, we have a text box or bounding rectangle that contains it. The text align specifies which part of that bounding box has to be aligned to the given coordinates. For example: drawing "POOP" at (0, 0) with a centered align means that the center of the text box will be aligned to the (0, 0) coordinate. We should see the bottom half of "OP" on the top-left corner of our rendering Target.

See Renderer.SetAlign() for further explanations.

const (
	// Horizontal aligns
	Left       Align = 0b0010_0000
	HorzCenter Align = 0b0100_0000
	Right      Align = 0b1000_0000

	// Vertical aligns
	Top          Align = 0b0000_0001 // top of font's ascent
	CapLine      Align = 0b0000_0011 // top of font's cap height (rarely used)
	Midline      Align = 0b0000_0010 // top of xheight (rarely used)
	VertCenter   Align = 0b0000_1001 // middle of line height
	Baseline     Align = 0b0000_0100 // aligned to baseline
	Bottom       Align = 0b0000_1000 // bottom of font's descent
	LastBaseline Align = 0b0000_1100 // last Baseline (for multiline text)

	// Full aligns
	Center Align = HorzCenter | VertCenter
)

Aligns have a vertical and a horizontal component. To set both components at once you can use a bitwise OR (e.g. Renderer.SetAlign(etxt.Left | etxt.Bottom)). To retrieve or compare the individual components, avoid bitwise operations and use Align.Vert() and Align.Horz() instead.

func (Align) Adjusted added in v0.0.9

func (self Align) Adjusted(align Align) Align

Returns the result of overriding the current align with the non-empty components of the given align. If both components are defined for the given align, the result will be the given align itself. If only one component is defined, only that component will be overwritten. If the given align is completely empty, the value of the current align will be returned unmodified.

func (Align) GetHorzAnchor added in v0.0.9

func (self Align) GetHorzAnchor(left, right int) int

Returns a value between 'left' and 'right' based on the current horizontal align:

  • Left: the function returns 'left'.
  • Right: the function returns 'right'.
  • Otherwise: the function returns the middle point between 'left' and 'right'.

func (Align) HasHorzComponent added in v0.0.9

func (self Align) HasHorzComponent() bool

Returns whether the align has a horizontal component.

func (Align) HasVertComponent added in v0.0.9

func (self Align) HasVertComponent() bool

Returns whether the align has a vertical component.

func (Align) Horz added in v0.0.9

func (self Align) Horz() Align

Returns the horizontal component of the align. If the align is valid, the result can only be Left, HorzCenter or Right.

func (Align) String added in v0.0.9

func (self Align) String() string

Returns a textual description of the align. Some examples:

(Top | Right).String() == "(Top | Right)"
(Right | Top).String() == "(Top | Right)"
Center.String() == "(VertCenter | HorzCenter)"
(Baseline | Left).String() == "(Baseline | Left)"
HorzCenter.String() == "(HorzCenter)"
Bottom.String() == "(Bottom)"

func (Align) Vert added in v0.0.9

func (self Align) Vert() Align

Returns the vertical component of the align. If the align is valid, the result can only be Top, CapLine, Midline, VertCenter, Baseline, LastBaseline or Bottom.

type BlendMode added in v0.0.9

type BlendMode = ebiten.Blend

The blend mode specifies how to compose colors when drawing glyphs:

  • Without Ebitengine, the blend mode can be BlendOver, BlendReplace, BlendAdd, BlendSub, BlendMultiply, BlendCut and BlendHue.
  • With Ebitengine, the blend mode is Ebitengine's Blend.

I only ever change blend modes to make cutout text, but there's a lot of weird people out there, what can I say.

type Direction

type Direction int8

Renderers can have their text direction configured as left-to-right or right-to-left. See Renderer.SetDirection() for further context and details.

If necessary, directions can also be casted directly to unicode/bidi directions:

bidi.Direction(etxt.LeftToRight).
const (
	LeftToRight Direction = iota
	RightToLeft
)

func (Direction) String added in v0.0.9

func (self Direction) String() string

Returns the string representation of the Direction (e.g., "LeftToRight", "RightToLeft").

type Feed

type Feed struct {
	Renderer       *Renderer       // associated renderer
	Position       fract.Point     // the feed's working pen position or origin
	LineBreakX     fract.Unit      // the x coordinate set after a line break
	LineBreakAcc   uint16          // consecutive accumulated line breaks
	PrevGlyphIndex sfnt.GlyphIndex // previous glyph index. used for kern
}

Feeds are the lowest level mechanism to draw text in etxt, allowing the user to issue each glyph draw call individually and modifying positions or configurations in between.

As a rule of thumb, you should only resort to feeds if neither Renderer.Draw(), [RendererTwine.Draw]() nor RendererGlyph.SetDrawFunc() give you enough control to do what you want.

func NewFeed added in v0.0.9

func NewFeed(renderer *Renderer) *Feed

Creates a Feed associated to the given Renderer.

Feeds are the lowest level mechanism to draw text in etxt, as they expose and allow one to modify the drawing position manually.

Notice that the high coupling to the renderer makes working with feeds potentially finicky and unsafe. In most cases, creating a feed for each function where a feed is required is the sanest approach.

func (*Feed) Advance

func (self *Feed) Advance(codePoint rune)

Advances the feed's position without drawing anything.

func (*Feed) AdvanceGlyph

func (self *Feed) AdvanceGlyph(glyphIndex sfnt.GlyphIndex)

Advances the feed's position without drawing anything.

func (*Feed) At added in v0.0.9

func (self *Feed) At(x, y int) *Feed

Handy method to set the feed's Position and LineBreakX fields. Often chained on feed creation as follows:

feed := etxt.NewFeed(renderer).At(x, y)

Notice that the given y will be adjusted based on the associated renderer's align. While feeds can't automatically align text because the content to work with isn't known ahead of time, the vertical align is considered in this method in order to set the Position.Y field to its baseline value.

For more precise positioning, you can always manipulate the Position field directly.

func (*Feed) Draw

func (self *Feed) Draw(target Target, codePoint rune)

Draws the given rune and advances the feed's Position. The drawing configuration is taken from the feed's associated renderer.

Quantization will be checked before every drawing operation and adjusted if necessary (even vertical quantization).

func (*Feed) DrawGlyph

func (self *Feed) DrawGlyph(target Target, glyphIndex sfnt.GlyphIndex)

Same as Feed.Draw(), but taking a glyph index instead of a rune.

func (*Feed) LineBreak

func (self *Feed) LineBreak()

Advances the feed's position with a line break.

func (*Feed) Reset added in v0.0.9

func (self *Feed) Reset()

Utility method for setting all the feed fields to their zero values. After a reset, you will need to set the feed's Renderer field manually if you want to use it again.

type Font

type Font = sfnt.Font

A handy type alias for sfnt.Font so you don't need to import it separately when working with etxt.

type FontIndex

type FontIndex uint8

See [RendererTwine.RegisterFont]() and related functions.

When using multiple fonts, you are encouraged to define and use your own named constants within the relevant context. For example:

const (
    RegularFont etxt.FontIndex = iota
    BoldFont
    ItalicFont
)
const NextFontIndex FontIndex = 255

Special value for [RendererTwine.RegisterFont]().

type GlyphIndex

type GlyphIndex = sfnt.GlyphIndex

Glyph indices are used to specify which font glyph are we working with. They allow us to reference font glyphs that aren't mapped to any unicode code point (rune).

This type is a direct alias of sfnt.GlyphIndex so you don't have to import a separate package when working with [TwineMotionFunc] or custom functions for RendererGlyph.SetDrawFunc(). Everywhere else in the documentation sfnt.GlyphIndex is used, but they are completely interchangeable.

type GlyphMask

type GlyphMask = *ebiten.Image

A GlyphMask is the image that results from rasterizing a glyph. You rarely need to use glyph masks directly unless you are working with advanced functions or custom caches.

Without Ebitengine, GlyphMask defaults to *image.Alpha. The image bounds are adjusted to allow drawing the glyph at its intended position. In particular, bounds.Min.Y is typically negative, with y = 0 corresponding to the glyph's baseline, y < 0 to the ascending portions and y > 0 to the descending ones.

With Ebitengine, GlyphMask defaults to *ebiten.Image.

type LineChangeDetails added in v0.0.9

type LineChangeDetails struct {
	IsWrap      bool
	ElidedSpace bool
}

Helper type for RendererGlyph.SetLineChangeFunc().

type Renderer

type Renderer struct {
	// contains filtered or unexported fields
}

The Renderer is the heart of etxt and the type around which everything else revolves.

Renderers have three groups of functions:

  • Simple functions to adjust basic text properties like font, size, color, align, etc.
  • Simple functions to draw and measure text.
  • Gateways to access more advanced or specific functionality.

Gateways are auxiliary types that group specialized functions together and keep them out of the way for most workflows that won't require them. The current gateways are the following:

  • Renderer.Utils(), to access non-essential but handy functions.
  • Renderer.Fract(), to access specialized fractional positioning functionality.
  • Renderer.Glyph(), to access low level functions for glyphs and glyph masks.

To create a renderer, using NewRenderer() is recommended. Before you can start using it, though, you have to set a font. In most practical scenarios you will also want to set a cache, the text size, the text color and the align explicitly.

If you need further help or guidance, consider reading "advice on renderers" and going through the code in the examples folder.

func NewRenderer

func NewRenderer() *Renderer

Creates a new Renderer, initialized with reasonable default values.

Setting a font through Renderer.SetFont() or similar is required before being able to operate with it. You almost always want to set a cache right from the start too, with RendererUtils.SetCache8MiB() being the simplest solution.

func (*Renderer) Draw

func (self *Renderer) Draw(target Target, text string, x, y int)

Draws the given text with the current configuration (font, size, color, target, etc). The text drawing position is determined by the given pixel coordinates and the renderer's align (see Renderer.SetAlign() rules).

Missing glyphs in the current font will cause the renderer to panic. See RendererGlyph.GetRuneIndex() for further advice if you need to make your system more robust.

func (*Renderer) DrawWithWrap added in v0.0.9

func (self *Renderer) DrawWithWrap(target Target, text string, x, y, widthLimit int)

Same as Renderer.Draw(), but using a width limit for line wrapping. The algorithm is a trivial greedy algorithm that only considers spaces as line wrapping candidates.

The widthLimit must be given in real pixels, not logical units. This means that unlike text sizes, the widthLimit won't be internally multiplied by the renderer's scale factor.

func (*Renderer) Fract added in v0.0.9

func (self *Renderer) Fract() *RendererFract

[Gateway] to RendererFract functionality.

func (*Renderer) GetAlign

func (self *Renderer) GetAlign() Align

Returns the current align. See Renderer.SetAlign() documentation for further details.

func (*Renderer) GetBlendMode added in v0.0.9

func (self *Renderer) GetBlendMode() BlendMode

Returns the renderer's BlendMode. As far as I know, this is only strictly necessary when implementing draw operations with custom shaders.

func (*Renderer) GetBuffer added in v0.0.9

func (self *Renderer) GetBuffer() *sfnt.Buffer

Exposes the renderer's internal *sfnt.Buffer. This is unfortunately necessary for advanced interaction with the sfnt package and the sizer.Sizer interface.

func (*Renderer) GetCacheHandler

func (self *Renderer) GetCacheHandler() cache.GlyphCacheHandler

Returns the current glyph cache handler, which is nil by default.

Rarely used unless you are examining the cache handler manually.

func (*Renderer) GetColor

func (self *Renderer) GetColor() color.Color

Returns the current drawing color.

func (*Renderer) GetDirection added in v0.0.9

func (self *Renderer) GetDirection() Direction

Returns the current text direction. See Renderer.SetDirection() for more details.

func (*Renderer) GetFont

func (self *Renderer) GetFont() *sfnt.Font

Returns the current font. The font is nil by default.

func (*Renderer) GetScale added in v0.0.9

func (self *Renderer) GetScale() float64

Returns the current display scaling factor used for the text as a float64. See Renderer.SetScale() for further context and details.

func (*Renderer) GetSize added in v0.0.9

func (self *Renderer) GetSize() float64

Returns the current logical font size. By default, NewRenderer() sets the value to 16, but you are encouraged to always initialize your font size explicitly.

Notice that the returned value doesn't take scaling into account (see Renderer.SetScale()).

func (*Renderer) GetSizer

func (self *Renderer) GetSizer() sizer.Sizer

Returns the current sizer.Sizer.

The most common use for sizers is adjusting line height or glyph interspacing. Outside of that, sizers can also be relevant when trying to obtain information about font metrics or when making custom glyph mask rasterizers; all fairly uncommon things for the average user to have to worry about.

func (*Renderer) Glyph added in v0.0.9

func (self *Renderer) Glyph() *RendererGlyph

[Gateway] to RendererGlyph functionality.

func (*Renderer) Measure added in v0.0.9

func (self *Renderer) Measure(text string) fract.Rect

Returns the dimensions of the area taken by the given text. Intuitively, this matches the shaded area that you see when highlighting or selecting text in browsers and text editors.

The results are affected by the renderer's font, size, quantization, sizer and text direction.

Notice that overshoot or spilling (content falling outside the returned rect) are possible, but in general you shouldn't be worrying about it. Barring extreme cases and bad fonts, you should use small margins for your text and just trust that typographers know what they are doing with overshoot.

That being said, it's still true that italics, fancy display typefaces and script fonts are more prone to spill and may be safer to use with more generous margins than other types of fonts.

func (*Renderer) MeasureWithWrap added in v0.0.9

func (self *Renderer) MeasureWithWrap(text string, widthLimit int) fract.Rect

Same as Renderer.Measure(), but using a width limit for line wrapping. Typically used in conjunction with Renderer.DrawWithWrap().

The widthLimit must be given in real pixels, not logical units. This means that unlike text sizes, the widthLimit won't be internally multiplied by the renderer's scale factor.

The returned rect dimensions are always quantized, but the width doesn't take into account final spaces in the wrapped lines. Notice that the returned rect's minimum width may exceed widthLimit if the widthLimit is very low and there's some glyph in the text that exceeds it (a single glyph can't be split into multiple lines).

func (*Renderer) SetAlign

func (self *Renderer) SetAlign(align Align)

The renderer's Align defines how Renderer.Draw() and other operations interpret the coordinates passed to them. For example:

  • If the align is set to (etxt.Top | etxt.Left), coordinates will be interpreted as the top-left corner of the box that the text needs to occupy.
  • If the align is set to (etxt.Center), coordinates will be interpreted as the center of the box that the text needs to occupy.

See this image for a visual explanation instead.

Notice that aligns have a horizontal and a vertical component, so you can use Renderer.SetAlign(etxt.Right) and similar to change only one of the components at a time. See Align.Adjusted() for more details.

By default, NewRenderer() initializes the align to (etxt.Baseline | etxt.Left).

func (*Renderer) SetBlendMode added in v0.0.9

func (self *Renderer) SetBlendMode(blendMode BlendMode)

Sets the blend mode to be used on subsequent operations. The default blend mode will compose glyphs over the active target with regular alpha blending.

func (*Renderer) SetCacheHandler

func (self *Renderer) SetCacheHandler(cacheHandler cache.GlyphCacheHandler)

Sets the glyph cache handler used by the renderer. By default, no cache is used, but you almost always want to set one.

The easiest way is to use RendererUtils.SetCache8MiB(). If that's not suitable for your use-case, the general approach is to create a cache manually, obtain a cache handler from it and set it:

glyphsCache := cache.NewDefaultCache(16*1024*1024) // 16MiB cache
renderer.SetCacheHandler(glyphsCache.NewHandler())

See cache.NewDefaultCache() for more details.

A cache handler can only be used with a single renderer, but you may create multiple handlers from the same underlying cache and use them with different renderers.

func (*Renderer) SetColor

func (self *Renderer) SetColor(fontColor color.Color)

Sets the color to be used on subsequent draw operations. By default, NewRenderer() initializes the color to white.

func (*Renderer) SetDirection

func (self *Renderer) SetDirection(dir Direction)

Sets the text direction to be used on subsequent operations. By default, the direction is LeftToRight.

Do not confuse text direction with horizontal align. Text direction is typically only changed for right-to-left languages like Arabic, Hebrew or Persian.

Notice that etxt is not really at a point where it can handle complex scripts properly; if that's an important feature for you, consider ebiten/v2/text/v2 instead.

func (*Renderer) SetFont

func (self *Renderer) SetFont(font *sfnt.Font)

Sets the font to be used on subsequent operations. Without a font, a renderer is fundamentally useless, so do not forget to set one!

Miscellaneous tips and advice:

func (*Renderer) SetScale added in v0.0.9

func (self *Renderer) SetScale(scale float64)

Sets the display scaling factor to be used for the text size on subsequent operations.

If you need more context on display scaling, please read this guide. Understanding scaling in general is critical if you want to be able to render sharp text across different devices.

The scale must be non-negative. By default, NewRenderer() initializes it to 1.0.

func (*Renderer) SetSize added in v0.0.9

func (self *Renderer) SetSize(size float64)

Sets the logical font size to be used on subsequent operations. Sizes are given in pixels and can't be negative. Maximum size is limited around ~16K. By default, NewRenderer() initializes the size to 16px.

The relationship between font size and the size of its glyphs is complicated and can vary a lot between fonts, but to provide a general reference:

  • A capital latin letter is usually around 70% as tall as the given size. E.g.: at 16px, "A" will be 10-12px tall.
  • A lowercase latin letter is usually around 48% as tall as the given size. E.g.: at 16px, "x" will be 7-9px tall.

See also Renderer.SetScale() for proper handling of high resolution text and display scaling.

func (*Renderer) SetSizer

func (self *Renderer) SetSizer(fontSizer sizer.Sizer)

Sets the sizer to be used on subsequent operations.

The most common use for sizers is adjusting line height or glyph interspacing. Outside of that, sizers can also be relevant when trying to obtain information about font metrics or when making custom glyph mask rasterizers; all fairly uncommon things for the average user to have to worry about.

func (*Renderer) Utils added in v0.0.9

func (self *Renderer) Utils() *RendererUtils

[Gateway] to RendererUtils functionality.

type RendererFract added in v0.0.9

type RendererFract Renderer

This type exists only for documentation and structuring purposes, acting as a gateway to perform operations with fractional units.

Fractional units allow us to operate with a higher level of precision when drawing or measuring text. The use-cases for this are rather limited, though; as a rule of thumb, ignore these advanced features unless you find yourself really needing them.

In general, this type is used through method chaining:

renderer.Fract().Draw(canvas, text, x, y)

All the fractional operations depend on the fract.Unit type, so make sure to check out the fract subpackage if you need more context to understand how everything ties together.

func (*RendererFract) Draw added in v0.0.9

func (self *RendererFract) Draw(target Target, text string, x, y fract.Unit)

Fractional and lower level version of Renderer.Draw().

func (*RendererFract) DrawWithWrap added in v0.0.9

func (self *RendererFract) DrawWithWrap(target Target, text string, x, y fract.Unit, widthLimit int)

Fractional and lower level version of Renderer.DrawWithWrap().

func (*RendererFract) GetQuantization added in v0.0.9

func (self *RendererFract) GetQuantization() (horz, vert fract.Unit)

Returns the current horizontal and vertical quantization levels.

func (*RendererFract) GetScale added in v0.0.9

func (self *RendererFract) GetScale() fract.Unit

Fractional and lower level version of Renderer.GetScale().

func (*RendererFract) GetScaledSize added in v0.0.9

func (self *RendererFract) GetScaledSize() fract.Unit

Returns the scaled text size (logicalSize*scale).

Having access to the renderer's scaled font size is useful when working with sizers and trying to obtain specific metrics for advanced use-cases.

func (*RendererFract) GetSize added in v0.0.9

func (self *RendererFract) GetSize() fract.Unit

Fractional and lower level version of Renderer.GetSize().

func (*RendererFract) SetHorzQuantization added in v0.0.9

func (self *RendererFract) SetHorzQuantization(horz fract.Unit)

Sets the horizontal quantization level to be used on subsequent operations. Valid values are limited to the existing Qt constants (e.g. QtNone, QtFull, QtHalf).

By default, NewRenderer() initializes the horizontal quantization to Qt4th. This is generally a reasonable compromise between quality and performance... unless you are using pixel-art-like fonts; in that case, setting the quantization to QtFull is much preferable.

See also RendererFract.SetVertQuantization().

func (*RendererFract) SetScale added in v0.0.9

func (self *RendererFract) SetScale(scale fract.Unit)

Fractional and lower level version of Renderer.SetScale().

func (*RendererFract) SetSize added in v0.0.9

func (self *RendererFract) SetSize(size fract.Unit)

Fractional and lower level version of Renderer.SetSize().

func (*RendererFract) SetVertQuantization added in v0.0.9

func (self *RendererFract) SetVertQuantization(horz fract.Unit)

Sets the vertical quantization level to be used on subsequent operations. Valid values are limited to the existing Qt constants (e.g. Qt4th, Qt8th, Qt16th).

By default, NewRenderer() initializes the vertical quantization to QtFull. Most languages are written horizontally, so you almost never want to pay the price for high vertical positioning resolution.

See also RendererFract.SetHorzQuantization().

type RendererGlyph added in v0.0.9

type RendererGlyph Renderer

This type exists only for documentation and structuring purposes, acting as a gateway to perform low level operations related to raw font glyphs and rasterizers.

In general, this type is used through method chaining:

renderer.Glyph().LoadMask(glyphIndex, origin)

This type also uses fractional units for many operations, so it's advisable to be familiar with RendererFract and the etxt/fract subpackage before diving in.

func (*RendererGlyph) CacheIndex added in v0.0.9

func (self *RendererGlyph) CacheIndex(index sfnt.GlyphIndex)

Caches the given glyph with the current font and scaled size. The caching is attempted for each fractional position allowed by the current quantization configuration.

To obtain a glyph index from a rune, consider RendererGlyph.GetRuneIndex().

Notice that the success of this method depends on the renderer's cache configuration too. If there's no cache, the cache doesn't have enough capacity or you are using a custom cache with an unusual caching policy, results may not be what you expect.

func (*RendererGlyph) DrawMask added in v0.0.9

func (self *RendererGlyph) DrawMask(target Target, mask GlyphMask, origin fract.Point)

Default glyph drawing function. This is a very low level function, almost only relevant if you are trying to implement custom draw functions for RendererGlyph.SetDrawFunc().

Important: this function will not apply any quantization to the given origin position. If you want to respect the quantization levels currently configured on the renderer and you have computed the origin point on your own, you must quantize manually.

func (*RendererGlyph) GetRasterizer added in v0.0.9

func (self *RendererGlyph) GetRasterizer() mask.Rasterizer

Returns the current glyph mask rasterizer.

This function is only useful when working with configurable rasterizers; if you are only using the default glyph mask rasterizer you can probably ignore it.

Mask rasterizers are not concurrent-safe, so be careful with what you do after retrieving them.

func (*RendererGlyph) GetRuneIndex added in v0.0.9

func (self *RendererGlyph) GetRuneIndex(codePoint rune) sfnt.GlyphIndex

Obtains the glyph index for the given rune in the current renderer's font. This method returns 0 if the glyph mapping doesn't exist. The RendererGlyph.SetMissHandler() configuration is not considered here.

If you need more details about missing code points, consider font.GetMissingRunes(), or the manual approach:

buffer := renderer.GetBuffer()
font := renderer.GetFont()
index, err := font.GlyphIndex(buffer, codePoint)
if err != nil { /* handle */ }
if index == 0 { /* handle notdef glyph */ }

func (*RendererGlyph) LoadMask added in v0.0.9

func (self *RendererGlyph) LoadMask(index sfnt.GlyphIndex, origin fract.Point) GlyphMask

Loads a glyph mask. This is a very low level function, almost only relevant if you are trying to implement custom draw functions for RendererGlyph.SetDrawFunc().

func (*RendererGlyph) SetDrawFunc added in v0.0.9

func (self *RendererGlyph) SetDrawFunc(drawFn func(Target, sfnt.GlyphIndex, fract.Point))

Overrides the renderer's glyph drawing function with a custom one. You can set it to nil to go back to the default behavior.

The default implementation is a streamlined equivalent of:

mask := renderer.Glyph().LoadMask(glyphIndex, origin)
renderer.Glyph().DrawMask(target, mask, origin)

(Check out examples/ebiten/colorful and examples/ebiten/shaking if you need practical usage examples)

Changing renderer properties dynamically on the glyph drawing function is generally unsafe and many behaviors are undefined. Only the text color can be safely changed at the moment.

func (*RendererGlyph) SetLineChangeFunc added in v0.0.9

func (self *RendererGlyph) SetLineChangeFunc(lineChangeFn func(LineChangeDetails))

Sets a function to be called when processing a line break during draw operations. This can be used to detect line wrap space elisions, track draw indices more precisely and a few other advanced use-cases.

func (*RendererGlyph) SetMissHandler added in v0.0.9

func (self *RendererGlyph) SetMissHandler(missHandler func(*sfnt.Font, rune) (sfnt.GlyphIndex, bool))

By default, if the renderer can't map a given code point to a suitable glyph while drawing, the program will panic. Setting a missHandler allows you to override this behavior and use a glyph index of your choosing instead.

The miss handler can also return true in order to completely skip the code point.

For some common implementations, see OnMissSkip and OnMissNotdef. More complex approaches include logging and attempting to transliterate non-ASCII characters to their closest ASCII look-alikes.

func (*RendererGlyph) SetRasterizer added in v0.0.9

func (self *RendererGlyph) SetRasterizer(rasterizer mask.Rasterizer)

Sets the glyph mask rasterizer to be used on subsequent operations.

type RendererUtils added in v0.0.9

type RendererUtils Renderer

This type exists only for documentation and structuring purposes, acting as a gateway to utility functions for a Renderer.

In general, this type is used through method chaining:

renderer.Utils().SetCache8MiB()

The focus of this type are non-essential but handy functions that can make it easier to set up Renderer properties or perform certain operations. Most programs on etxt/examples/ebiten make use of this.

func (*RendererUtils) AssertMaxStoredStates added in v0.0.9

func (self *RendererUtils) AssertMaxStoredStates(n int)

Panics when the size of the stored states stack exceeds the given value. States are stored with RendererUtils.StoreState().

There are two main ways to use this function:

  • Regularly asserting that the number of stored states stays below a reasonable limit for your use-case in order to prevent memory leaks.
  • Passing zero whenever you want to ensure that the states stack is completely empty.

func (*RendererUtils) FillMissingProperties added in v0.0.9

func (self *RendererUtils) FillMissingProperties()

Sets default values for any uninitialized properties that are required to make the renderer produce visible results, except for the font. Notice that this also excludes the cache handler.

This function exists solely to soothe troubled souls; solid reasons to use it in practice might never be found.

func (*RendererUtils) GetLineHeight added in v0.0.9

func (self *RendererUtils) GetLineHeight() float64

Utility method to get the current line height. Functionally equivalent to:

font   := renderer.GetFont()
buffer := renderer.GetBuffer()
size   := renderer.Fract().GetScaledSize()
sizer  := renderer.GetSizer()
lineHeight := sizer.LineHeight(font, buffer, size).ToFloat64()

func (*RendererUtils) RestoreState added in v0.0.9

func (self *RendererUtils) RestoreState() bool

The counterpart of RendererUtils.StoreState(). Restores the most recently stored renderer state and removes it from the internal stack.

Iff the states stack is empty and no state restoration is possible, the function returns false.

func (*RendererUtils) SetCache8MiB added in v0.0.9

func (self *RendererUtils) SetCache8MiB()

Utility method to set a cache that will get you started. For a more manual and adjustable approach, see Renderer.SetCacheHandler() instead.

func (*RendererUtils) SetFontBytes added in v0.0.9

func (self *RendererUtils) SetFontBytes(data []byte) error

Utility method to set the font by passing its raw data and letting the renderer parse it. This method should be avoided if you want to reuse the font data at different points in your application; in that case, parsing the font only once and setting it with Renderer.SetFont() is the way to go.

For more advanced font management functionality, see etxt/font.Library.

func (*RendererUtils) StoreState added in v0.0.9

func (self *RendererUtils) StoreState()

Makes a copy of the current renderer state and pushes it into an internal stack. Stored states can be recovered with RendererUtils.RestoreState() in last-in first-out order.

The stored state includes the following properties:

Notably, custom rendering functions, inactive fonts and the cache handler are not stored.

For improved safety when managing states, consider also RendererUtils.AssertMaxStoredStates().

type Target added in v0.0.9

type Target = *ebiten.Image

Alias to allow compiling the package without Ebitengine (-tags gtxt).

Without Ebitengine, Target defaults to image/draw.Image.

Directories

Path Synopsis
The cache subpackage defines the GlyphCacheHandler interface used within etxt and provides a default cache implementation.
The cache subpackage defines the GlyphCacheHandler interface used within etxt and provides a default cache implementation.
examples
ebiten/aligns Module
ebiten/bbcode Module
ebiten/cutout Module
ebiten/twine Module
ebiten/words Module
The font subpackage contains helper methods to parse fonts and obtain information from them (id, name, family, etc.), alongisde a Library type to assist with their management if necessary.
The font subpackage contains helper methods to parse fonts and obtain information from them (id, name, family, etc.), alongisde a Library type to assist with their management if necessary.
CPU-based vectorial text rendering has always been a performance sensitive task, with glyph rasterization being one of the most critical steps in the process.
CPU-based vectorial text rendering has always been a performance sensitive task, with glyph rasterization being one of the most critical steps in the process.
The mask subpackage defines the Rasterizer interface used within etxt and provides multiple ready-to-use implementations.
The mask subpackage defines the Rasterizer interface used within etxt and provides multiple ready-to-use implementations.
The sizer subpackage defines the Sizer interface used within etxt and provides multiple ready-to-use implementations.
The sizer subpackage defines the Sizer interface used within etxt and provides multiple ready-to-use implementations.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL