Start loading .fnt files. No display yet
This commit is contained in:
133
internal/fonts/fonts.go
Normal file
133
internal/fonts/fonts.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package fonts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"ur.gs/ordoor/internal/util"
|
||||
"ur.gs/ordoor/internal/util/asciiscan"
|
||||
)
|
||||
|
||||
type Font struct {
|
||||
Name string
|
||||
// Contains the sprite data for the font. FIXME: load this?
|
||||
ObjectFile string
|
||||
|
||||
// Maps ASCII bytes to a sprite offset in the ObjectFile
|
||||
mapping map[int]int
|
||||
}
|
||||
|
||||
func (f *Font) Entries() int {
|
||||
return len(f.mapping)
|
||||
}
|
||||
|
||||
// Returns the offsets required to display a given string, returning an error if
|
||||
// some of the runes in the string are unknown to the font
|
||||
func (f *Font) Indices(s string) ([]int, error) {
|
||||
out := make([]int, 0, len(s))
|
||||
|
||||
for i, b := range []byte(s) {
|
||||
|
||||
offset, ok := f.mapping[int(b)]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Unknown codepoint %v at offset %v in string %s", b, i, s)
|
||||
}
|
||||
|
||||
out = append(out, offset)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func LoadFont(filename string) (*Font, error) {
|
||||
scanner, err := asciiscan.New(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer scanner.Close()
|
||||
|
||||
// First, load the object file name
|
||||
objFile, err := scanner.ConsumeString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := &Font{
|
||||
Name: filepath.Base(filename),
|
||||
ObjectFile: objFile,
|
||||
mapping: make(map[int]int),
|
||||
}
|
||||
|
||||
for {
|
||||
str, err := scanner.ConsumeString()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parseErr := fmt.Errorf("Invalid entry in %v: %q", filename, str)
|
||||
fields := strings.Fields(str)
|
||||
|
||||
switch fields[0] {
|
||||
case "done":
|
||||
goto out
|
||||
case "r": // A range of codepoints
|
||||
if len(fields) < 5 {
|
||||
return nil, parseErr
|
||||
}
|
||||
|
||||
cpStart, _ := strconv.Atoi(fields[1])
|
||||
cpEnd, _ := strconv.Atoi(fields[2])
|
||||
idxStart, _ := strconv.Atoi(fields[3])
|
||||
idxEnd, _ := strconv.Atoi(fields[4])
|
||||
size := idxEnd - idxStart
|
||||
|
||||
// FIXME: I'd love this to be an error but several .fnt files do it
|
||||
if cpEnd-cpStart != size {
|
||||
fmt.Printf("WARNING: %v has mismatched codepoints and indices: %q\n", filename, str)
|
||||
}
|
||||
|
||||
for offset := 0; offset < size; offset++ {
|
||||
out.mapping[cpStart+offset] = idxStart + offset
|
||||
}
|
||||
case "v": // A single codepoint, 4 fields
|
||||
if len(fields) < 3 {
|
||||
return nil, parseErr
|
||||
}
|
||||
|
||||
cp, _ := strconv.Atoi(fields[1])
|
||||
idx, _ := strconv.Atoi(fields[2])
|
||||
|
||||
out.mapping[cp] = idx
|
||||
default:
|
||||
return nil, parseErr
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func LoadFonts(dir string) (map[string]*Font, error) {
|
||||
files, err := util.DirByExt(dir, ".fnt")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out := make(map[string]*Font, len(files))
|
||||
|
||||
for _, file := range files {
|
||||
abs := filepath.Join(dir, file)
|
||||
base := filepath.Base(file)
|
||||
font, err := LoadFont(abs)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %v", abs, err)
|
||||
}
|
||||
|
||||
out[base] = font
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
Reference in New Issue
Block a user