Example #1
0
func generateAtlas(font *truetype.Font, scale int32, dpi float64, width, height float32) ([]Vector4, *image.RGBA, []float32) {
	var low rune = 32
	var high rune = 127
	glyphCount := int32(high - low + 1)
	offsets := make([]float32, glyphCount)

	bounds := font.Bounds(scale)
	gw := float32(bounds.XMax - bounds.XMin)
	gh := float32(bounds.YMax - bounds.YMin)
	imageWidth := glh.Pow2(uint32(gw * float32(glyphCount)))
	imageHeight := glh.Pow2(uint32(gh))
	imageBounds := image.Rect(0, 0, int(imageWidth), int(imageHeight))
	sx := float32(2) / width
	sy := float32(2) / height
	w := gw * sx
	h := gh * sy
	img := image.NewRGBA(imageBounds)
	c := freetype.NewContext()
	c.SetDst(img)
	c.SetClip(img.Bounds())
	c.SetSrc(image.White)
	c.SetDPI(dpi)
	c.SetFontSize(float64(scale))
	c.SetFont(font)

	var gi int32
	var gx, gy float32
	verts := make([]Vector4, 0)
	texWidth := float32(img.Bounds().Dx())
	texHeight := float32(img.Bounds().Dy())

	for ch := low; ch <= high; ch++ {
		index := font.Index(ch)
		metric := font.HMetric(scale, index)

		//the offset is used when drawing a string of glyphs - we will advance a glyph's quad by the width of all previous glyphs in the string
		offsets[gi] = float32(metric.AdvanceWidth) * sx

		//draw the glyph into the atlas at the correct location
		pt := freetype.Pt(int(gx), int(gy)+int(c.PointToFix32(float64(scale))>>8))
		c.DrawString(string(ch), pt)

		tx1 := gx / texWidth
		ty1 := gy / texHeight
		tx2 := (gx + gw) / texWidth
		ty2 := (gy + gh) / texHeight

		//the x,y coordinates are the same for each quad; only the texture coordinates (stored in z,w) change.
		//an optimization would be to only store texture coords, but I haven't figured that out yet
		verts = append(verts, Vector4{-1, 1, tx1, ty1},
			Vector4{-1 + (w), 1, tx2, ty1},
			Vector4{-1, 1 - (h), tx1, ty2},
			Vector4{-1 + (w), 1 - (h), tx2, ty2})

		gx += gw
		gi++
	}
	return verts, img, offsets
}
Example #2
0
// LoadTruetype loads a truetype font from the given stream and
// applies the given font scale in points.
//
// The low and high values determine the lower and upper rune limits
// we should load for this font. For standard ASCII this would be: 32, 127.
//
// The dir value determines the orientation of the text we render
// with this font. This should be any of the predefined Direction constants.
func LoadTruetype(r io.Reader, scale int32, low, high rune, dir Direction) (*Font, error) {
	data, err := ioutil.ReadAll(r)
	if err != nil {
		return nil, err
	}

	// Read the truetype font.
	ttf, err := truetype.Parse(data)
	if err != nil {
		return nil, err
	}

	// Create our FontConfig type.
	var fc FontConfig
	fc.Dir = dir
	fc.Low = low
	fc.High = high
	fc.Glyphs = make(Charset, high-low+1)

	// Create an image, large enough to store all requested glyphs.
	//
	// We limit the image to 16 glyphs per row. Then add as many rows as
	// needed to encompass all glyphs, while making sure the resulting image
	// has power-of-two dimensions.
	gc := int32(len(fc.Glyphs))
	glyphsPerRow := int32(16)
	glyphsPerCol := (gc / glyphsPerRow) + 1

	gb := ttf.Bounds(scale)
	gw := (gb.XMax - gb.XMin)
	gh := (gb.YMax - gb.YMin) + 5
	iw := glh.Pow2(uint32(gw * glyphsPerRow))
	ih := glh.Pow2(uint32(gh * glyphsPerCol))

	rect := image.Rect(0, 0, int(iw), int(ih))
	img := image.NewRGBA(rect)

	// Use a freetype context to do the drawing.
	c := freetype.NewContext()
	c.SetDPI(72)
	c.SetFont(ttf)
	c.SetFontSize(float64(scale))
	c.SetClip(img.Bounds())
	c.SetDst(img)
	c.SetSrc(image.White)

	// Iterate over all relevant glyphs in the truetype font and
	// draw them all to the image buffer.
	//
	// For each glyph, we also create a corresponding Glyph structure
	// for our Charset. It contains the appropriate glyph coordinate offsets.
	var gi int
	var gx, gy int32

	for ch := low; ch <= high; ch++ {
		index := ttf.Index(ch)
		metric := ttf.HMetric(scale, index)

		fc.Glyphs[gi].Advance = int(metric.AdvanceWidth)
		fc.Glyphs[gi].X = int(gx)
		fc.Glyphs[gi].Y = int(gy)
		fc.Glyphs[gi].Width = int(gw)
		fc.Glyphs[gi].Height = int(gh)

		pt := freetype.Pt(int(gx), int(gy)+int(c.PointToFix32(float64(scale))>>8))
		c.DrawString(string(ch), pt)

		if gi%16 == 0 {
			gx = 0
			gy += gh
		} else {
			gx += gw
		}

		gi++
	}

	return loadFont(img, &fc)
}