1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-11-06 18:27:20 -05:00
OpenDiablo2/d2render/d2ui/font.go

124 lines
3.0 KiB
Go
Raw Normal View History

2019-11-10 08:51:02 -05:00
package d2ui
2019-10-25 19:37:04 -04:00
import (
"image/color"
"strings"
2019-11-10 03:36:53 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2helper"
2019-11-10 08:51:02 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2data/d2datadict"
2019-11-10 03:36:53 -05:00
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2render"
"github.com/hajimehoshi/ebiten"
2019-10-25 19:37:04 -04:00
)
var fontCache = map[string]*Font{}
// FontSize represents the size of a character in a font
type FontSize struct {
Width uint8
Height uint8
}
// Font represents a font
type Font struct {
2019-11-10 10:44:13 -05:00
fontSprite d2render.Sprite
metrics map[uint8]FontSize
2019-10-25 19:37:04 -04:00
}
// GetFont creates or loads an existing font
2019-11-10 03:36:53 -05:00
func GetFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font {
2019-10-25 19:37:04 -04:00
cacheItem, exists := fontCache[font+"_"+string(palette)]
if exists {
return cacheItem
}
newFont := CreateFont(font, palette, fileProvider)
fontCache[font+"_"+string(palette)] = newFont
return newFont
}
// CreateFont creates an instance of a MPQ Font
2019-11-10 03:36:53 -05:00
func CreateFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font {
2019-10-25 19:37:04 -04:00
result := &Font{
metrics: make(map[uint8]FontSize),
2019-10-25 19:37:04 -04:00
}
2019-11-10 08:51:02 -05:00
result.fontSprite = d2render.CreateSprite(fileProvider.LoadFile(font+".dc6"), d2datadict.Palettes[palette])
2019-10-25 19:37:04 -04:00
woo := "Woo!\x01"
fontData := fileProvider.LoadFile(font + ".tbl")
if string(fontData[0:5]) != woo {
panic("No woo :(")
}
for i := 12; i < len(fontData); i += 14 {
fontSize := FontSize{
Width: fontData[i+3],
Height: fontData[i+4],
}
result.metrics[fontData[i+8]] = fontSize
2019-10-25 19:37:04 -04:00
}
return result
}
// GetTextMetrics returns the size of the specified text
func (v *Font) GetTextMetrics(text string) (width, height uint32) {
width = uint32(0)
curWidth := uint32(0)
height = uint32(0)
maxCharHeight := uint32(0)
2019-10-27 02:58:37 -04:00
for _, m := range v.fontSprite.Frames {
2019-11-10 03:36:53 -05:00
maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height))
}
for i := 0; i < len(text); i++ {
ch := text[i]
if ch == '\n' {
2019-11-10 03:36:53 -05:00
width = d2helper.Max(width, curWidth)
curWidth = 0
height += maxCharHeight + 6
continue
}
metric := v.metrics[uint8(ch)]
curWidth += uint32(metric.Width)
}
2019-11-10 03:36:53 -05:00
width = d2helper.Max(width, curWidth)
height += maxCharHeight
return
}
// Draw draws the font on the target surface
func (v *Font) Draw(x, y int, text string, color color.Color, target *ebiten.Image) {
v.fontSprite.ColorMod = color
2019-10-26 00:06:54 -04:00
v.fontSprite.Blend = false
maxCharHeight := uint32(0)
for _, m := range v.metrics {
2019-11-10 03:36:53 -05:00
maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height))
}
targetWidth, _ := target.Size()
lines := strings.Split(text, "\n")
for lineIdx, line := range lines {
lineWidth, _ := v.GetTextMetrics(line)
xPos := x + ((targetWidth / 2) - int(lineWidth/2))
for _, ch := range line {
char := uint8(ch)
metric := v.metrics[char]
v.fontSprite.Frame = char
2019-10-27 02:58:37 -04:00
v.fontSprite.MoveTo(xPos, y+int(v.fontSprite.Frames[char].Height))
v.fontSprite.Draw(target)
xPos += int(metric.Width)
}
if lineIdx >= len(lines)-1 {
break
}
xPos = x
y += int(maxCharHeight + 6)
}
}