2019-10-25 19:37:04 -04:00
|
|
|
package UI
|
|
|
|
|
|
|
|
import (
|
2019-10-25 22:20:36 -04:00
|
|
|
"image/color"
|
2019-10-26 23:59:27 -04:00
|
|
|
"strings"
|
2019-10-25 22:20:36 -04:00
|
|
|
|
2019-11-02 17:38:39 -04:00
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/Common"
|
|
|
|
"github.com/OpenDiablo2/OpenDiablo2/PaletteDefs"
|
2019-10-25 22:20:36 -04:00
|
|
|
"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-10-25 22:20:36 -04:00
|
|
|
fontSprite *Common.Sprite
|
|
|
|
metrics map[uint8]FontSize
|
2019-10-25 19:37:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetFont creates or loads an existing font
|
2019-11-01 14:12:23 -04:00
|
|
|
func GetFont(font string, palette PaletteDefs.PaletteType, fileProvider Common.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-01 14:12:23 -04:00
|
|
|
func CreateFont(font string, palette PaletteDefs.PaletteType, fileProvider Common.FileProvider) *Font {
|
2019-10-25 19:37:04 -04:00
|
|
|
result := &Font{
|
2019-10-25 22:20:36 -04:00
|
|
|
metrics: make(map[uint8]FontSize),
|
2019-10-25 19:37:04 -04:00
|
|
|
}
|
2019-10-25 22:20:36 -04:00
|
|
|
result.fontSprite = fileProvider.LoadSprite(font+".dc6", 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],
|
|
|
|
}
|
2019-10-25 22:20:36 -04:00
|
|
|
result.metrics[fontData[i+8]] = fontSize
|
2019-10-25 19:37:04 -04:00
|
|
|
}
|
|
|
|
return result
|
|
|
|
}
|
2019-10-25 22:20:36 -04:00
|
|
|
|
|
|
|
// GetTextMetrics returns the size of the specified text
|
|
|
|
func (v *Font) GetTextMetrics(text string) (width, height uint32) {
|
|
|
|
width = uint32(0)
|
2019-10-26 23:59:27 -04:00
|
|
|
curWidth := uint32(0)
|
2019-10-25 22:20:36 -04:00
|
|
|
height = uint32(0)
|
2019-10-26 23:59:27 -04:00
|
|
|
maxCharHeight := uint32(0)
|
2019-10-27 02:58:37 -04:00
|
|
|
for _, m := range v.fontSprite.Frames {
|
2019-10-26 23:59:27 -04:00
|
|
|
maxCharHeight = Common.Max(maxCharHeight, uint32(m.Height))
|
|
|
|
}
|
2019-10-26 02:11:28 -04:00
|
|
|
for i := 0; i < len(text); i++ {
|
|
|
|
ch := text[i]
|
2019-10-26 23:59:27 -04:00
|
|
|
if ch == '\n' {
|
|
|
|
width = Common.Max(width, curWidth)
|
|
|
|
curWidth = 0
|
|
|
|
height += maxCharHeight + 6
|
|
|
|
continue
|
|
|
|
}
|
2019-10-25 22:20:36 -04:00
|
|
|
metric := v.metrics[uint8(ch)]
|
2019-10-26 23:59:27 -04:00
|
|
|
curWidth += uint32(metric.Width)
|
2019-10-25 22:20:36 -04:00
|
|
|
}
|
2019-10-26 23:59:27 -04:00
|
|
|
width = Common.Max(width, curWidth)
|
|
|
|
height += maxCharHeight
|
2019-10-25 22:20:36 -04:00
|
|
|
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
|
2019-10-26 23:59:27 -04:00
|
|
|
|
|
|
|
maxCharHeight := uint32(0)
|
|
|
|
for _, m := range v.metrics {
|
|
|
|
maxCharHeight = Common.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))
|
2019-10-26 23:59:27 -04:00
|
|
|
v.fontSprite.Draw(target)
|
|
|
|
xPos += int(metric.Width)
|
|
|
|
}
|
|
|
|
|
|
|
|
if lineIdx >= len(lines)-1 {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
xPos = x
|
|
|
|
y += int(maxCharHeight + 6)
|
2019-10-25 22:20:36 -04:00
|
|
|
}
|
|
|
|
}
|