Skip to content

Commit db0b670

Browse files
committed
Move loading fonts to a new font package
This is not a core functionality. Game developer does not have to load fonts manually, because system and custom fonts are loaded automatically.
1 parent e8df573 commit db0b670

12 files changed

+65
-77
lines changed

internal/font/font.go renamed to font/font.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,40 @@
44
package font
55

66
import (
7+
"bytes"
78
"fmt"
89

910
"github.com/elgopher/pi/image"
1011
)
1112

12-
// Load gets non-zero pixels from the font sheet and converts them to font data understood by π.
13-
// The result is inserted into fontData slice.
13+
// Load loads font-sheet (png image) and converts
14+
// it to font data. Image must be 128x128. Each char is 8x8.
15+
// Char 0 is in the top-left corner. Char 1 to the right.
1416
//
15-
// Img must be 128x128. Each char is 8x8. Char 0 is in the top-left corner. Char 1 to the right.
17+
// This function can be used if you want to use 3rd font:
1618
//
17-
// fontData must have length of 2048.
18-
func Load(img image.Image, fontData []byte) error {
19+
// myFont := pi.Font{Width:4, WidthSpecial:8, Height: 8}
20+
// pi.Load(png, myFont.Data[:])
21+
//
22+
// Color with index 0 is treated as background. Any other color
23+
// as foreground.
24+
//
25+
// The result is inserted into fontData slice. The size of slice must
26+
// be 2048.
27+
func Load(png []byte, fontData []byte) error {
28+
img, err := image.DecodePNG(bytes.NewReader(png))
29+
if err != nil {
30+
return fmt.Errorf("decoding font failed: %w", err)
31+
}
32+
33+
if err = load(img, fontData[:]); err != nil {
34+
return fmt.Errorf("error system font: %w", err)
35+
}
36+
37+
return nil
38+
}
39+
40+
func load(img image.Image, fontData []byte) error {
1941
const (
2042
charWidth, charHeight = 8, 8 // in pixels
2143
rows, cells = 16, 16 // number of rows and cells in font sheet

internal/font/font_test.go renamed to font/font_test.go

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,40 @@
44
package font_test
55

66
import (
7-
"bytes"
87
_ "embed"
98
"testing"
109

11-
"github.com/elgopher/pi/image"
12-
"github.com/elgopher/pi/internal/font"
1310
"github.com/stretchr/testify/assert"
1411
"github.com/stretchr/testify/require"
12+
13+
"github.com/elgopher/pi/font"
1514
)
1615

17-
//go:embed font_test.png
18-
var testFont []byte
16+
var (
17+
//go:embed internal/invalid-width.png
18+
invalidWidthImage []byte
19+
20+
//go:embed internal/invalid-height.png
21+
invalidHeightImage []byte
22+
23+
//go:embed internal/valid.png
24+
validImage []byte
25+
26+
//go:embed internal/empty.png
27+
emptyImage []byte
28+
)
1929

2030
func TestLoadImageInto(t *testing.T) {
21-
t.Run("should return error for invalid image", func(t *testing.T) {
22-
tests := map[string]image.Image{
23-
"width not 128": {Width: 1, Height: 128, Pixels: make([]byte, 128)},
24-
"height not 128": {Width: 128, Height: 1, Pixels: make([]byte, 128)},
25-
"invalid number of pixels": {Width: 128, Height: 128, Pixels: make([]byte, 128)},
31+
t.Run("should return error when font png is invalid", func(t *testing.T) {
32+
var out [2048]byte
33+
err := font.Load(make([]byte, 0), out[:])
34+
require.Error(t, err)
35+
})
36+
37+
t.Run("should return error for invalid image size", func(t *testing.T) {
38+
tests := map[string][]byte{
39+
"width not 128": invalidWidthImage,
40+
"height not 128": invalidHeightImage,
2641
}
2742
for name, img := range tests {
2843
t.Run(name, func(t *testing.T) {
@@ -34,15 +49,13 @@ func TestLoadImageInto(t *testing.T) {
3449
})
3550

3651
t.Run("should return error for invalid fontData", func(t *testing.T) {
37-
img := image.Image{Width: 128, Height: 128, Pixels: make([]byte, 128*128)}
3852
var out [1]byte
39-
err := font.Load(img, out[:])
53+
err := font.Load(validImage, out[:])
4054
assert.Error(t, err)
4155
})
4256

4357
t.Run("should override existing data", func(t *testing.T) {
4458
out := makeNotZeroSlice(2048, 1)
45-
emptyImage := image.Image{Width: 128, Height: 128, Pixels: make([]byte, 128*128)}
4659
// when
4760
err := font.Load(emptyImage, out)
4861
require.NoError(t, err)
@@ -51,10 +64,8 @@ func TestLoadImageInto(t *testing.T) {
5164

5265
t.Run("should load pixels", func(t *testing.T) {
5366
out := make([]byte, 2048)
54-
img, err := image.DecodePNG(bytes.NewReader(testFont))
55-
require.NoError(t, err)
5667
// when
57-
err = font.Load(img, out)
68+
err := font.Load(validImage, out)
5869
// then
5970
require.NoError(t, err)
6071
expectedChar0 := []byte{1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80}

font/internal/empty.png

126 Bytes
Loading

font/internal/invalid-height.png

111 Bytes
Loading

font/internal/invalid-width.png

113 Bytes
Loading
File renamed without changes.
-101 Bytes
Binary file not shown.

pi.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"fmt"
1515
"io/fs"
1616

17+
"github.com/elgopher/pi/font"
1718
"github.com/elgopher/pi/vm"
1819
)
1920

@@ -108,15 +109,15 @@ func Boot() error {
108109
return err
109110
}
110111

111-
if err := LoadFontData(systemFontPNG, vm.SystemFont.Data[:]); err != nil {
112+
if err := font.Load(systemFontPNG, vm.SystemFont.Data[:]); err != nil {
112113
return err
113114
}
114115

115116
if Resources == nil {
116117
Resources = embed.FS{}
117118
}
118119

119-
if err := loadResources(Resources); err != nil {
120+
if err := loadGameResources(Resources); err != nil {
120121
return err
121122
}
122123

@@ -162,7 +163,7 @@ func validateUserParameters() error {
162163
return nil
163164
}
164165

165-
func loadResources(resources fs.ReadFileFS) error {
166+
func loadGameResources(resources fs.ReadFileFS) error {
166167
if err := loadSpriteSheet(resources); err != nil {
167168
return err
168169
}

pi_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package pi_test
55

66
import (
7+
_ "embed"
78
"strconv"
89
"testing"
910
"testing/fstest"
@@ -15,6 +16,9 @@ import (
1516
"github.com/elgopher/pi/vm"
1617
)
1718

19+
//go:embed internal/testimage/custom-font.png
20+
var customFont []byte
21+
1822
func TestBoot(t *testing.T) {
1923
const color = 7
2024

@@ -113,7 +117,7 @@ func TestBoot(t *testing.T) {
113117
t.Run("should load custom-font.png", func(t *testing.T) {
114118
pi.Reset()
115119
pi.Resources = fstest.MapFS{
116-
"custom-font.png": &fstest.MapFile{Data: customFontPng},
120+
"custom-font.png": &fstest.MapFile{Data: customFont},
117121
}
118122
// when
119123
err := pi.Boot()

print.go

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@
44
package pi
55

66
import (
7-
"bytes"
87
_ "embed"
98
"errors"
109
"fmt"
1110
"io/fs"
1211

13-
"github.com/elgopher/pi/image"
14-
"github.com/elgopher/pi/internal/font"
12+
"github.com/elgopher/pi/font"
1513
"github.com/elgopher/pi/vm"
1614
)
1715

@@ -100,27 +98,6 @@ func (f Font) printRune(r rune, sx, sy int, color byte) int {
10098
}
10199
}
102100

103-
// LoadFontData loads font-sheet (png image) and converts
104-
// it to font data. Image must be 128x128. Each char is 8x8.
105-
// Char 0 is in the top-left corner. Char 1 to the right.
106-
//
107-
// This function can be used if you want to use 3rd font:
108-
//
109-
// myFont := pi.Font{Width:4, WidthSpecial:8,Height: 8}
110-
// pi.LoadFontData(png, myFont.Data[:])
111-
func LoadFontData(png []byte, out []byte) error {
112-
img, err := image.DecodePNG(bytes.NewReader(png))
113-
if err != nil {
114-
return fmt.Errorf("decoding font failed: %w", err)
115-
}
116-
117-
if err = font.Load(img, out[:]); err != nil {
118-
return fmt.Errorf("error system font: %w", err)
119-
}
120-
121-
return nil
122-
}
123-
124101
func loadCustomFont(resources fs.ReadFileFS) error {
125102
fileContents, err := resources.ReadFile("custom-font.png")
126103
if errors.Is(err, fs.ErrNotExist) {
@@ -131,5 +108,5 @@ func loadCustomFont(resources fs.ReadFileFS) error {
131108
return fmt.Errorf("error loading custom-font.png file: %w", err)
132109
}
133110

134-
return LoadFontData(fileContents, vm.CustomFont.Data[:])
111+
return font.Load(fileContents, vm.CustomFont.Data[:])
135112
}

print_test.go

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -147,30 +147,3 @@ func assertScreenEqual(t *testing.T, file string) {
147147
fmt.Println("Screenshot taken", screenshot)
148148
}
149149
}
150-
151-
//go:embed internal/testimage/print/custom-font.png
152-
var customFontPng []byte
153-
154-
//go:embed internal/testimage/print/custom-font-too-small.png
155-
var customFontTooSmall []byte
156-
157-
func TestLoadFontData(t *testing.T) {
158-
t.Run("should return error when font png is invalid", func(t *testing.T) {
159-
font := pi.Font{}
160-
err := pi.LoadFontData(make([]byte, 0), font.Data[:])
161-
require.Error(t, err)
162-
})
163-
164-
t.Run("should return error when png is valid but too small", func(t *testing.T) {
165-
font := pi.Font{}
166-
err := pi.LoadFontData(customFontTooSmall, font.Data[:])
167-
require.Error(t, err)
168-
})
169-
170-
t.Run("should decode png file into font data", func(t *testing.T) {
171-
font := pi.Font{}
172-
err := pi.LoadFontData(customFontPng, font.Data[:])
173-
require.NoError(t, err)
174-
assert.Equal(t, byte(0b00001111), font.Data[0])
175-
})
176-
}

0 commit comments

Comments
 (0)