package assetstore import ( "fmt" "log" "github.com/hajimehoshi/ebiten" "code.ur.gs/lupine/ordoor/internal/fonts" ) type Font struct { Name string mapping map[rune]*Sprite } func (a *AssetStore) Font(name string) (*Font, error) { name = canonical(name) // FIXME: these fonts don't exist. For now, point at one that does. switch name { case "imfnt13", "imfnt14": name = "wh40k_12" } if font, ok := a.fonts[name]; ok { return font, nil } log.Printf("Loading font %v", name) filename, err := a.lookup(name, "fnt", "Fonts") if err != nil { return nil, err } raw, err := fonts.LoadFont(filename) if err != nil { return nil, err } objFile, err := a.lookup(raw.ObjectFile, "", "Fonts") if err != nil { return nil, err } obj, err := a.ObjectByPath(objFile) if err != nil { return nil, err } out := &Font{ Name: name, mapping: make(map[rune]*Sprite, len(raw.Mapping)), } for r, offset := range raw.Mapping { spr, err := obj.Sprite(offset) if err != nil { return nil, err } out.mapping[r] = spr } a.fonts[name] = out return out, nil } // FIXME: this violates the ebiten rules for fast drawing. We may need to do the // draw ourselves, with image.Paletted for each glyph to a single ebiten.Image // // FIXME: it'd be great if we didn't have to implement this all by ourselves; // golang.org/x/image/font and github.com/hajimehoshi/ebiten/text are *almost* // sufficient, but don't seem to like it when the glyphs are literal colours // instead of a mask. // // TODO: draw text in a bounding box, multiple lines, etc func (f *Font) DrawLine(text string) (*ebiten.Image, error) { sprites := make([]*Sprite, 0, len(text)) width := 0 height := 0 for _, r := range text { spr, ok := f.mapping[r] if !ok { return nil, fmt.Errorf("Font %v does not specify rune %v", f.Name, r) } width += spr.Rect.Dx() if y := spr.Rect.Dy(); y > height { height = y } sprites = append(sprites, spr) } img, err := ebiten.NewImage(width, height, ebiten.FilterDefault) if err != nil { return nil, err } xOff := 0 for _, spr := range sprites { op := &ebiten.DrawImageOptions{} op.GeoM.Translate(float64(xOff), 0) xOff += spr.Rect.Dx() if err := img.DrawImage(spr.Image, op); err != nil { return nil, err } } return img, nil }