package d2ui import ( "image/color" "strings" "github.com/OpenDiablo2/OpenDiablo2/d2helper" "github.com/OpenDiablo2/OpenDiablo2/d2data/d2datadict" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface" "github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum" "github.com/OpenDiablo2/OpenDiablo2/d2render" "github.com/hajimehoshi/ebiten" ) 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 { fontSprite d2render.Sprite metrics map[uint8]FontSize } // GetFont creates or loads an existing font func GetFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font { 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 func CreateFont(font string, palette d2enum.PaletteType, fileProvider d2interface.FileProvider) *Font { result := &Font{ metrics: make(map[uint8]FontSize), } result.fontSprite = d2render.CreateSprite(fileProvider.LoadFile(font+".dc6"), d2datadict.Palettes[palette]) 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 } 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) for _, m := range v.fontSprite.Frames { maxCharHeight = d2helper.Max(maxCharHeight, uint32(m.Height)) } for i := 0; i < len(text); i++ { ch := text[i] if ch == '\n' { width = d2helper.Max(width, curWidth) curWidth = 0 height += maxCharHeight + 6 continue } metric := v.metrics[uint8(ch)] curWidth += uint32(metric.Width) } 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 v.fontSprite.Blend = false maxCharHeight := uint32(0) for _, m := range v.metrics { 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 = int16(char) 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) } }