mirror of
https://github.com/OpenDiablo2/OpenDiablo2
synced 2025-02-04 15:46:51 -05:00
129 lines
2.5 KiB
Go
129 lines
2.5 KiB
Go
|
package d2bitmapfont
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"image/color"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
|
||
|
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2math"
|
||
|
)
|
||
|
|
||
|
func New(s d2interface.Sprite, table []byte, col color.Color) *BitmapFont {
|
||
|
return &BitmapFont{
|
||
|
Sprite: s,
|
||
|
Table: table,
|
||
|
Color: col,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
type Glyph struct {
|
||
|
frame int
|
||
|
width int
|
||
|
height int
|
||
|
}
|
||
|
|
||
|
// BitmapFont represents a rasterized font, made from a font Table, sprite, and palette
|
||
|
type BitmapFont struct {
|
||
|
Sprite d2interface.Sprite
|
||
|
Table []byte
|
||
|
Glyphs map[rune]Glyph
|
||
|
Color color.Color
|
||
|
}
|
||
|
|
||
|
// SetColor sets the fonts Color
|
||
|
func (f *BitmapFont) SetColor(c color.Color) {
|
||
|
f.Color = c
|
||
|
}
|
||
|
|
||
|
// GetTextMetrics returns the dimensions of the BitmapFont element in pixels
|
||
|
func (f *BitmapFont) GetTextMetrics(text string) (width, height int) {
|
||
|
if f.Glyphs == nil {
|
||
|
f.initGlyphs()
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
lineWidth int
|
||
|
lineHeight int
|
||
|
)
|
||
|
|
||
|
for _, c := range text {
|
||
|
if c == '\n' {
|
||
|
width = d2math.MaxInt(width, lineWidth)
|
||
|
height += lineHeight
|
||
|
lineWidth = 0
|
||
|
lineHeight = 0
|
||
|
} else if glyph, ok := f.Glyphs[c]; ok {
|
||
|
lineWidth += glyph.width
|
||
|
lineHeight = d2math.MaxInt(lineHeight, glyph.height)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
width = d2math.MaxInt(width, lineWidth)
|
||
|
height += lineHeight
|
||
|
|
||
|
return width, height
|
||
|
}
|
||
|
|
||
|
// RenderText prints a text using its configured style on a Surface (multi-lines are left-aligned, use label otherwise)
|
||
|
func (f *BitmapFont) RenderText(text string, target d2interface.Surface) error {
|
||
|
if f.Glyphs == nil {
|
||
|
f.initGlyphs()
|
||
|
}
|
||
|
|
||
|
f.Sprite.SetColorMod(f.Color)
|
||
|
|
||
|
lines := strings.Split(text, "\n")
|
||
|
|
||
|
for _, line := range lines {
|
||
|
var (
|
||
|
lineHeight int
|
||
|
lineLength int
|
||
|
)
|
||
|
|
||
|
for _, c := range line {
|
||
|
glyph, ok := f.Glyphs[c]
|
||
|
if !ok {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
if err := f.Sprite.SetCurrentFrame(glyph.frame); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
f.Sprite.Render(target)
|
||
|
|
||
|
lineHeight = d2math.MaxInt(lineHeight, glyph.height)
|
||
|
lineLength++
|
||
|
|
||
|
target.PushTranslation(glyph.width, 0)
|
||
|
}
|
||
|
|
||
|
target.PopN(lineLength)
|
||
|
target.PushTranslation(0, lineHeight)
|
||
|
}
|
||
|
|
||
|
target.PopN(len(lines))
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (f *BitmapFont) initGlyphs() {
|
||
|
_, maxCharHeight := f.Sprite.GetFrameBounds()
|
||
|
|
||
|
glyphs := make(map[rune]Glyph)
|
||
|
|
||
|
for i := 12; i < len(f.Table); i += 14 {
|
||
|
code := rune(binary.LittleEndian.Uint16(f.Table[i : i+2]))
|
||
|
|
||
|
var glyph Glyph
|
||
|
glyph.frame = int(binary.LittleEndian.Uint16(f.Table[i+8 : i+10]))
|
||
|
glyph.width = int(f.Table[i+3])
|
||
|
glyph.height = maxCharHeight
|
||
|
|
||
|
glyphs[code] = glyph
|
||
|
}
|
||
|
|
||
|
f.Glyphs = glyphs
|
||
|
}
|