aminal/vendor/github.com/liamg/glfont/font.go

240 lines
5.8 KiB
Go

package glfont
import (
"os"
"github.com/go-gl/gl/all-core/gl"
)
// Direction represents the direction in which strings should be rendered.
type Direction uint8
// Known directions.
const (
LeftToRight Direction = iota // E.g.: Latin
RightToLeft // E.g.: Arabic
TopToBottom // E.g.: Chinese
)
// A Font allows rendering of text to an OpenGL context.
type Font struct {
fontChar []*character
vao uint32
vbo uint32
program uint32
texture uint32 // Holds the glyph texture id.
color color
}
type color struct {
r float32
g float32
b float32
a float32
}
//LoadFont loads the specified font at the given scale.
func LoadFont(file string, scale int32, windowWidth int, windowHeight int) (*Font, error) {
fd, err := os.Open(file)
if err != nil {
return nil, err
}
defer fd.Close()
// Configure the default font vertex and fragment shaders
program, err := newProgram(vertexFontShader, fragmentFontShader)
if err != nil {
panic(err)
}
// Activate corresponding render state
gl.UseProgram(program)
//set screen resolution
resUniform := gl.GetUniformLocation(program, gl.Str("resolution\x00"))
gl.Uniform2f(resUniform, float32(windowWidth), float32(windowHeight))
return LoadTrueTypeFont(program, fd, scale, 32, 127, LeftToRight)
}
//SetColor allows you to set the text color to be used when you draw the text
func (f *Font) SetColor(red float32, green float32, blue float32, alpha float32) {
f.color.r = red
f.color.g = green
f.color.b = blue
f.color.a = alpha
}
func (f *Font) UpdateResolution(windowWidth int, windowHeight int) {
gl.UseProgram(f.program)
resUniform := gl.GetUniformLocation(f.program, gl.Str("resolution\x00"))
gl.Uniform2f(resUniform, float32(windowWidth), float32(windowHeight))
gl.UseProgram(0)
}
//Printf draws a string to the screen, takes a list of arguments like printf
func (f *Font) Print(x, y float32, scale float32, text string) error {
indices := []rune(text)
if len(indices) == 0 {
return nil
}
lowChar := rune(32)
//setup blending mode
gl.Enable(gl.BLEND)
gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA)
// Activate corresponding render state
gl.UseProgram(f.program)
//set text color
gl.Uniform4f(gl.GetUniformLocation(f.program, gl.Str("textColor\x00")), f.color.r, f.color.g, f.color.b, f.color.a)
//set screen resolution
//resUniform := gl.GetUniformLocation(f.program, gl.Str("resolution\x00"))
//gl.Uniform2f(resUniform, float32(2560), float32(1440))
gl.ActiveTexture(gl.TEXTURE0)
gl.BindVertexArray(f.vao)
// Iterate through all characters in string
for i := range indices {
//get rune
runeIndex := indices[i]
//skip runes that are not in font chacter range
if int(runeIndex)-int(lowChar) > len(f.fontChar) || runeIndex < lowChar {
continue
}
//find rune in fontChar list
ch := f.fontChar[runeIndex-lowChar]
//calculate position and size for current rune
xpos := x + float32(ch.bearingH)*scale
ypos := y - float32(ch.height-ch.bearingV)*scale
w := float32(ch.width) * scale
h := float32(ch.height) * scale
//set quad positions
var x1 = xpos
var x2 = xpos + w
var y1 = ypos
var y2 = ypos + h
//setup quad array
var vertices = []float32{
// X, Y, Z, U, V
// Front
x1, y1, 0.0, 0.0,
x2, y1, 1.0, 0.0,
x1, y2, 0.0, 1.0,
x1, y2, 0.0, 1.0,
x2, y1, 1.0, 0.0,
x2, y2, 1.0, 1.0}
// Render glyph texture over quad
gl.BindTexture(gl.TEXTURE_2D, ch.textureID)
// Update content of VBO memory
gl.BindBuffer(gl.ARRAY_BUFFER, f.vbo)
//BufferSubData(target Enum, offset int, data []byte)
gl.BufferSubData(gl.ARRAY_BUFFER, 0, len(vertices)*4, gl.Ptr(vertices)) // Be sure to use glBufferSubData and not glBufferData
// Render quad
gl.DrawArrays(gl.TRIANGLES, 0, 24)
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += float32((ch.advance >> 6)) * scale // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
//clear opengl textures and programs
gl.BindVertexArray(0)
gl.BindTexture(gl.TEXTURE_2D, 0)
gl.UseProgram(0)
gl.Disable(gl.BLEND)
return nil
}
//Width returns the width of a piece of text in pixels
func (f *Font) Width(scale float32, text string) float32 {
var width float32
indices := []rune(text)
if len(indices) == 0 {
return 0
}
lowChar := rune(32)
// Iterate through all characters in string
for i := range indices {
//get rune
runeIndex := indices[i]
//skip runes that are not in font chacter range
if int(runeIndex)-int(lowChar) > len(f.fontChar) || runeIndex < lowChar {
continue
}
//find rune in fontChar list
ch := f.fontChar[runeIndex-lowChar]
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
width += float32((ch.advance >> 6)) * scale // Bitshift by 6 to get value in pixels (2^6 = 64 (divide amount of 1/64th pixels by 64 to get amount of pixels))
}
return width
}
//Height returns the height of a piece of text in pixels
func (f *Font) Height(scale float32, text string) float32 {
var baseHeight float32
var height float32
indices := []rune(text)
if len(indices) == 0 {
return 0
}
lowChar := rune(32)
// Iterate through all characters in string
for i := range indices {
//get rune
runeIndex := indices[i]
if int(runeIndex) == 0x0a {
baseHeight = height
height = 0
}
//skip runes that are not in font chacter range
if int(runeIndex)-int(lowChar) > len(f.fontChar) || runeIndex < lowChar {
continue
}
//find rune in fontChar list
ch := f.fontChar[runeIndex-lowChar]
// Now advance cursors for next glyph (note that advance is number of 1/64 pixels)
if float32(ch.height)*scale > height {
height = float32(ch.height) * scale
}
}
return baseHeight + height
}