76 lines
1.6 KiB
Go
76 lines
1.6 KiB
Go
package font
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
|
|
"github.com/golang/freetype/truetype"
|
|
fontlib "golang.org/x/image/font"
|
|
|
|
"zworld/assets"
|
|
"zworld/engine/util"
|
|
)
|
|
|
|
var parseCache map[string]*truetype.Font = make(map[string]*truetype.Font, 32)
|
|
var faceCache map[string]T = make(map[string]T, 128)
|
|
|
|
func loadTruetypeFont(filename string) (*truetype.Font, error) {
|
|
// check parsed font cache
|
|
if fnt, exists := parseCache[filename]; exists {
|
|
return fnt, nil
|
|
}
|
|
|
|
fontBytes, err := assets.ReadAll(filename)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to load font: %w", err)
|
|
}
|
|
|
|
fnt, err := truetype.Parse(fontBytes)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to parse font: %w", err)
|
|
}
|
|
|
|
// add to cache
|
|
parseCache[filename] = fnt
|
|
return fnt, nil
|
|
}
|
|
|
|
func Load(filename string, size int, scale float32) T {
|
|
key := fmt.Sprintf("%s:%dx%.2f", filename, size, scale)
|
|
if font, exists := faceCache[key]; exists {
|
|
return font
|
|
}
|
|
|
|
ttf, err := loadTruetypeFont(filename)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
name := ttf.Name(truetype.NameIDFontFullName)
|
|
log.Printf("+ font %s %dpt x%.2f\n", name, size, scale)
|
|
|
|
dpi := 72.0 * scale
|
|
face := truetype.NewFace(ttf, &truetype.Options{
|
|
Size: float64(size),
|
|
DPI: float64(dpi),
|
|
Hinting: fontlib.HintingFull,
|
|
SubPixelsX: 8,
|
|
SubPixelsY: 8,
|
|
})
|
|
|
|
fnt := &font{
|
|
size: float32(size),
|
|
scale: scale,
|
|
name: name,
|
|
face: face,
|
|
glyphs: util.NewSyncMap[rune, *Glyph](),
|
|
kern: util.NewSyncMap[runepair, float32](),
|
|
drawer: &fontlib.Drawer{Face: face},
|
|
mutex: &sync.Mutex{},
|
|
}
|
|
|
|
faceCache[key] = fnt
|
|
return fnt
|
|
}
|