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()
}
Printf draws the given string at the specified coordinates.
It expects the string to be a single line. Line breaks are not
handled as line breaks and are rendered as glyphs.

In order to render multi-line text, it is up to the caller to split
the text up into individual lines of adequate length and then call
this method for each line seperately.
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
}