-
Notifications
You must be signed in to change notification settings - Fork 0
/
font.go
148 lines (132 loc) · 5.01 KB
/
font.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Copyright © 2014-2018 Galvanized Logic Inc.
// Use is governed by a BSD-style license found in the LICENSE file.
package vu
// font.go encapsulates knowledge for displaying strings on screen.
// Also see label.go.
//
// FUTURE: create 3D fonts from system fonts on the fly
// or make a separate tool like:
// http://www.angelcode.com/products/bmfont/
import (
"github.com/gazed/vu/render"
)
// font is font mapping data needed by MakeLabel.
// font holds a single bitmapped font. It knows how to pull individual
// character images out of a single image that contains all the characters
// for a font. It is combined with a texture (the font bitmapped image)
// in order to produce displayable strings.
type font struct {
name string // Unique id for a glyph set.
tag aid // Name and type as a number.
w, h int // Width and height of the entire font bitmap image.
chars map[rune]*char // The "character" image information.
// scratch variables reused to create rendered text phrases.
vb []float32 // verticies.
tb []float32 // texture mapping "uv" values.
fb []uint16 // triangle face indicies.
}
// newFont allocates space for font mapping data.
func newFont(name string) *font {
f := &font{name: name, tag: assetID(fnt, name)}
f.chars = map[rune]*char{}
return f
}
// aid is used to uniquely identify assets.
func (f *font) aid() aid { return f.tag } // hashed type and name.
func (f *font) label() string { return f.name } // asset name
// set font mapping data. Expected to be called by loader
// as fonts are loaded from disk.
func (f *font) setSize(w, h int) { f.w, f.h = w, h }
func (f *font) addChar(r rune, x, y, w, h, xo, yo, xa int) {
uvs := f.uvs(x, y, w, h)
f.chars[r] = &char{x, y, w, h, xo, yo, xa, uvs}
}
// setStr creates an image for the given string returning
// the verticies, and texture texture (uv) mapping information as
// a buffer slice.
// wrap : optional (positive) width limit before the text wraps.
//
// The width in pixels for the resulting string image is returned.
func (f *font) setStr(m *Mesh, str string, wrap int) (sx, sy int) {
vb := f.vb[:0] // reset keeping allocated memory.
tb := f.tb[:0] // ""
fb := f.fb[:0] // ""
// gather and arrange the letters for the phrase.
width, height, fh, cnt := 0, 0, 0, 0
for _, char := range str {
c := f.chars[char]
switch {
case c != nil:
fh = c.h // remember font height for wrapping with newlines.
tb = append(tb, c.uvcs...)
xo, yo := float32(c.xOffset), float32(c.yOffset)
if c.w != 0 && c.h != 0 {
// calculate the x, y positions based on desired locations.
vb = append(vb,
float32(width)+xo, float32(-height)+yo, 0, // upper left
float32(c.w+width)+xo, float32(-height)+yo, 0, // upper right
float32(c.w+width)+xo, float32(c.h-height)+yo, 0, // lower right
float32(width)+xo, float32(c.h-height)+yo, 0) // lower left
// keep track of the max size in pixels.
if sx < c.w+width {
sx = c.w + width
}
if sy < c.h+height {
sy = c.h + height
}
}
width += c.xAdvance
if wrap > 0 && (width > wrap && char == ' ') {
width = 0
height += c.h
}
// create the triangles indexes referring to the points above.
i0 := uint16(cnt * 4)
fb = append(fb, i0, i0+1, i0+3, i0+1, i0+2, i0+3)
cnt++ // count characters rendered.
case char == '\n':
// auto wrap at newlines.
width = 0
height += fh
}
}
m.InitData(0, 3, render.StaticDraw, false).SetData(0, vb)
m.InitData(2, 2, render.StaticDraw, false).SetData(2, tb)
m.InitFaces(render.StaticDraw).SetFaces(fb)
f.vb = vb // reuse the allocated memory.
f.tb = tb // ""
f.fb = fb // ""
return sx, sy
}
// uvs calculates the four UV points for one character. The x,y coordinates
// are the top left of the character. Note that the UV's are added to the array
// so as to match the order the vertices are created in panel(). This makes
// the letters appear the right way up rather than flipped.
//
// Expected to be used for loading fonts from disk.
func (f *font) uvs(x, y, w, h int) []float32 {
uvcs := []float32{
float32(x) / float32(f.w), // lower left
float32(y+h) / float32(f.h), // ""
float32(x+w) / float32(f.w), // lower right
float32(y+h) / float32(f.h), // ""
float32(x+w) / float32(f.w), // upper right
float32(y) / float32(f.h), // ""
float32(x) / float32(f.w), // upper left
float32(y) / float32(f.h), // ""
}
return uvcs
}
// font
// ===========================================================================
// char
// char represents a single bitmap character. Works well with
// http://www.angelcode.com/products/bmfont/doc/file_format.html
type char struct {
x, y int // Top left corner.
w, h int // Width and height.
xOffset int // Current position offset for texture to screen.
yOffset int // Current position offset for texture to screen.
xAdvance int // Current position advance after drawing character.
uvcs []float32 // Character bitmap texture coordinates 0:0, 1:0, 0:1, 1:1.
}