github.com/Kintar/etxt@v0.0.0-20221224033739-2fc69f000137/README.md (about)

     1  # etxt
     2  [![Go Reference](https://pkg.go.dev/badge/github.com/Kintar/etxt.svg)](https://pkg.go.dev/github.com/Kintar/etxt)
     3  
     4  **etxt** is a package for font management and text rendering in Golang designed to be used with the [**Ebitengine**](https://github.com/hajimehoshi/ebiten) game engine.
     5  
     6  While Ebitengine already provides the [**ebiten/text**](https://pkg.go.dev/github.com/hajimehoshi/ebiten/v2/text) package that makes *getting some text drawn on screen* easy enough, **etxt** aims to help you actually understand what you are doing, doing it in a structured way and giving you much more control over it.
     7  
     8  As a quick summary of what this package provides:
     9  - Structured font management and usage through the `FontLibrary` and `Renderer` types; because having to create and manage new `font.Face`s just to change text size is *not* ok.
    10  - Full control over glyph mask caching and rasterization (or just stay with the defaults!).
    11  - A few custom rasterizers that allow you to draw faux-bold, oblique, ~~blurred and hollow text~~ (WIP). Not really "main features", though, only examples of what you can do with **etxt**.
    12  - Lots of [examples](https://github.com/Kintar/etxt/tree/main/examples) and thorough documentation.
    13  
    14  ## Code example
    15  Less talk and more code!
    16  ```Golang
    17  package main
    18  
    19  import ( "log" ; "time" ; "image/color" )
    20  import "github.com/hajimehoshi/ebiten/v2"
    21  import "github.com/Kintar/etxt"
    22  
    23  type Game struct { txtRenderer *etxt.Renderer }
    24  func (self *Game) Layout(int, int) (int, int) { return 400, 400 }
    25  func (self *Game) Update() error { return nil }
    26  func (self *Game) Draw(screen *ebiten.Image) {
    27  	// hacky color computation
    28  	millis := time.Now().UnixMilli()
    29  	blue := (millis/16) % 512
    30  	if blue >= 256 { blue = 511 - blue }
    31  	changingColor := color.RGBA{ 0, 255, uint8(blue), 255 }
    32  
    33  	// set relevant text renderer properties and draw
    34  	self.txtRenderer.SetTarget(screen)
    35  	self.txtRenderer.SetColor(changingColor)
    36  	self.txtRenderer.Draw("Hello World!", 200, 200)
    37  }
    38  
    39  func main() {
    40  	// load font library
    41  	fontLib := etxt.NewFontLibrary()
    42  	_, _, err := fontLib.ParseDirFonts("game_dir/assets/fonts") // !!
    43  	if err != nil {
    44  		log.Fatalf("Error while loading fonts: %s", err.Error())
    45  	}
    46  
    47  	// check that we have the fonts we want
    48  	// (shown for completeness, you don't need this in most cases)
    49  	expectedFonts := []string{ "Roboto Bold", "Carter One" }  // !!
    50  	for _, fontName := range expectedFonts {
    51  		if !fontLib.HasFont(fontName) {
    52  			log.Fatal("missing font: " + fontName)
    53  		}
    54  	}
    55  
    56  	// check that the fonts have the characters we want
    57  	// (shown for completeness, you don't need this in most cases)
    58  	err = fontLib.EachFont(checkMissingRunes)
    59  	if err != nil { log.Fatal(err) }
    60  
    61  	// create a new text renderer and configure it
    62  	txtRenderer := etxt.NewStdRenderer()
    63  	glyphsCache := etxt.NewDefaultCache(10*1024*1024) // 10MB
    64  	txtRenderer.SetCacheHandler(glyphsCache.NewHandler())
    65  	txtRenderer.SetFont(fontLib.GetFont(expectedFonts[0]))
    66  	txtRenderer.SetAlign(etxt.YCenter, etxt.XCenter)
    67  	txtRenderer.SetSizePx(64)
    68  
    69  	// run the "game"
    70  	ebiten.SetWindowSize(400, 400)
    71  	err = ebiten.RunGame(&Game{ txtRenderer })
    72  	if err != nil { log.Fatal(err) }
    73  }
    74  
    75  // helper function used with FontLibrary.EachFont to make sure
    76  // all loaded fonts contain the characters or alphabet we want
    77  func checkMissingRunes(name string, font *etxt.Font) error {
    78  	const letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
    79  	const symbols = "0123456789 .,;:!?-()[]{}_&#@"
    80  
    81  	missing, err := etxt.GetMissingRunes(font, letters + symbols)
    82  	if err != nil { return err }
    83  	if len(missing) > 0 {
    84  		log.Fatalf("Font '%s' missing runes: %s", name, string(missing))
    85  	}
    86  	return nil
    87  }
    88  ```
    89  
    90  This example focuses on the mundane usage of the main **etxt** `FontLibrary` and `Renderer` types, with abundant checks to fail fast if anything seems out of place.
    91  
    92  If you want flashier examples you will find [many more](https://github.com/Kintar/etxt/tree/main/examples) in the project, make sure to check them out!
    93  
    94  ## Can I use this package without Ebitengine?
    95  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 stuff. In particular, be careful to not accidentally use `gtxt` with Ebitengine (they are compatible in many cases, but performance will die).
    96  
    97  ## Should I bother learning to use etxt?
    98  If you are only dealing with text rendering incidentally and **ebiten/text** does the job well enough for you, feel free to stay with that.
    99  
   100  The main consideration when using **etxt** is that you need to be minimally acquainted with how fonts work. [FreeType glyph conventions](https://freetype.org/freetype2/docs/glyphs/index.html) is the go to reference that you *really should be reading* (up to section IV or V).
   101  
   102  ## Any future plans?
   103  This package is already quite solid, there are only a few points left to improve:
   104  - Adding a few more effects (hollow text, shaders, etc).
   105  - Missing a couple important examples (crisp UI and shaders).
   106  
   107  If I get really bored, I'd also like to look into:
   108  - Contributing to Golang's **sfnt** to [expose more tables](https://github.com/golang/go/issues/45325) and allow the creation of minimal packages to do basic [text shaping](https://github.com/Kintar/etxt/blob/main/docs/shaping.md) in arabic or other complex scripts.
   109  - Add outline expansion. Freetype and libASS do this, and it would be quite nice to get high quality outlines and better faux-bolds... but it's also *hard*; I don't really know if I want to go there.
   110  - Triangulation and GPU rendering of Bézier curves are also interesting for Ebitengine (although they probably don't belong in this package).