func (f *Font) GlyphBounds() (int, int) {
	return f.maxGlyphWidth, f.maxGlyphHeight
}
GlyphBounds returns the largest width and height for any of the glyphs
in the font. This constitutes the largest possible bounding box
a single glyph will have.
package gltext
import (
	"fmt"
	"image"
	"unsafe"
	"github.com/go-gl/gl/v2.1/gl"
)
type Font struct {
	config         *FontConfig  
	texture        uint32       
	listbase       uint32       
	maxGlyphWidth  int          
	maxGlyphHeight int          
}
func loadFont(img *image.RGBA, config *FontConfig) (f *Font, err error) {
	f = new(Font)
	f.config = config
	img = Pow2Image(img).(*image.RGBA)
	ib := img.Bounds()
	gl.GenTextures(1, &f.texture)
	gl.BindTexture(gl.TEXTURE_2D, f.texture)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
	gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
	gl.TexImage2D(gl.TEXTURE_2D, 0, gl.RGBA, int32(ib.Dx()), int32(ib.Dy()), 0,
		gl.RGBA, gl.UNSIGNED_BYTE, gl.Ptr(img.Pix))
	f.listbase = gl.GenLists(int32(len(config.Glyphs)))
	texWidth := float32(ib.Dx())
	texHeight := float32(ib.Dy())
	for index, glyph := range config.Glyphs {
		if glyph.Width > f.maxGlyphWidth {
			f.maxGlyphWidth = glyph.Width
		}
		if glyph.Height > f.maxGlyphHeight {
			f.maxGlyphHeight = glyph.Height
		}
		vw := float32(glyph.Width)
		vh := float32(glyph.Height)
		tx1 := float32(glyph.X) / texWidth
		ty1 := float32(glyph.Y) / texHeight
		tx2 := (float32(glyph.X) + vw) / texWidth
		ty2 := (float32(glyph.Y) + vh) / texHeight
		adv := float32(glyph.Advance)
		gl.NewList(f.listbase+uint32(index), gl.COMPILE)
		{
			gl.Begin(gl.QUADS)
			{
				gl.TexCoord2f(tx1, ty2)
				gl.Vertex2f(0, 0)
				gl.TexCoord2f(tx2, ty2)
				gl.Vertex2f(vw, 0)
				gl.TexCoord2f(tx2, ty1)
				gl.Vertex2f(vw, vh)
				gl.TexCoord2f(tx1, ty1)
				gl.Vertex2f(0, vh)
			}
			gl.End()
			switch config.Dir {
			case LeftToRight:
				gl.Translatef(adv, 0, 0)
			case RightToLeft:
				gl.Translatef(-adv, 0, 0)
			case TopToBottom:
				gl.Translatef(0, -adv, 0)
			}
		}
		gl.EndList()
	}
	err = checkGLError()
	return
}
func (f *Font) Dir() Direction { return f.config.Dir }
func (f *Font) Low() rune { return f.config.Low }
func (f *Font) High() rune { return f.config.High }
func (f *Font) Glyphs() Charset { return f.config.Glyphs }
func (f *Font) Release() {
	gl.DeleteTextures(1, &f.texture)
	gl.DeleteLists(f.listbase, int32(len(f.config.Glyphs)))
	f.config = nil
}
func (f *Font) Metrics(text string) (int, int) {
	if len(text) == 0 {
		return 0, 0
	}
	gw, gh := f.GlyphBounds()
	if f.config.Dir == TopToBottom {
		return gw, f.advanceSize(text)
	}
	return f.advanceSize(text), gh
}
func (f *Font) advanceSize(line string) int {
	gw, gh := f.GlyphBounds()
	glyphs := f.config.Glyphs
	low := f.config.Low
	indices := []rune(line)
	var size int
	for _, r := range indices {
		r -= low
		if r >= 0 && int(r) < len(glyphs) {
			size += glyphs[r].Advance
			continue
		}
		if f.config.Dir == TopToBottom {
			size += gh
		} else {
			size += gw
		}
	}
	return size
}
func (f *Font) Printf(x, y float32, fs string, argv ...interface{}) error {
	indices := []rune(fmt.Sprintf(fs, argv...))
	if len(indices) == 0 {
		return nil
	}
	low := f.config.Low
	for i := range indices {
		indices[i] -= low
	}
	var vp [4]int32
	gl.GetIntegerv(gl.VIEWPORT, &vp[0])
	gl.PushAttrib(gl.TRANSFORM_BIT)
	gl.MatrixMode(gl.PROJECTION)
	gl.PushMatrix()
	gl.LoadIdentity()
	gl.Ortho(float64(vp[0]), float64(vp[2]), float64(vp[1]), float64(vp[3]), 0, 1)
	gl.PopAttrib()
	gl.PushAttrib(gl.LIST_BIT | gl.CURRENT_BIT | gl.ENABLE_BIT | gl.TRANSFORM_BIT)
	{
		gl.MatrixMode(gl.MODELVIEW)
		gl.Disable(gl.LIGHTING)
		gl.Disable(gl.DEPTH_TEST)
		gl.Enable(gl.BLEND)
		gl.Enable(gl.TEXTURE_2D)
		gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
		gl.TexEnvf(gl.TEXTURE_ENV, gl.TEXTURE_ENV_MODE, gl.MODULATE)
		gl.BindTexture(gl.TEXTURE_2D, f.texture)
		gl.ListBase(f.listbase)
		var mv [16]float32
		gl.GetFloatv(gl.MODELVIEW_MATRIX, &mv[0])
		gl.PushMatrix()
		{
			gl.LoadIdentity()
			mgw := float32(f.maxGlyphWidth)
			mgh := float32(f.maxGlyphHeight)
			switch f.config.Dir {
			case LeftToRight, TopToBottom:
				gl.Translatef(x, float32(vp[3])-y-mgh, 0)
			case RightToLeft:
				gl.Translatef(x-mgw, float32(vp[3])-y-mgh, 0)
			}
			gl.MultMatrixf(&mv[0])
			gl.CallLists(int32(len(indices)), gl.UNSIGNED_INT, unsafe.Pointer(&indices[0]))
		}
		gl.PopMatrix()
		gl.BindTexture(gl.TEXTURE_2D, 0)
	}
	gl.PopAttrib()
	gl.PushAttrib(gl.TRANSFORM_BIT)
	gl.MatrixMode(gl.PROJECTION)
	gl.PopMatrix()
	gl.PopAttrib()
	return checkGLError()
}