1
1
mirror of https://github.com/OpenDiablo2/OpenDiablo2 synced 2024-06-13 19:20:43 +00:00
OpenDiablo2/d2game/d2player/inventory.go

319 lines
7.1 KiB
Go
Raw Normal View History

package d2player
import (
2020-08-11 22:01:33 +00:00
"fmt"
"image/color"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2data/d2datadict"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2enum"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2interface"
"github.com/OpenDiablo2/OpenDiablo2/d2common/d2resource"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2asset"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2gui"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2item/diablo2item"
"github.com/OpenDiablo2/OpenDiablo2/d2core/d2ui"
)
2020-08-11 22:01:33 +00:00
// Inventory represents the inventory
type Inventory struct {
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
asset *d2asset.AssetManager
2020-08-11 22:01:33 +00:00
uiManager *d2ui.UIManager
frame *d2ui.Sprite
panel *d2ui.Sprite
grid *ItemGrid
hoverLabel *d2ui.Label
hoverX int
hoverY int
originX int
originY int
lastMouseX int
lastMouseY int
hovering bool
isOpen bool
}
2020-08-11 22:01:33 +00:00
// NewInventory creates an inventory instance and returns a pointer to it
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
func NewInventory(asset *d2asset.AssetManager, ui *d2ui.UIManager,
record *d2datadict.InventoryRecord) *Inventory {
hoverLabel := ui.NewLabel(d2resource.FontFormal11, d2resource.PaletteStatic)
hoverLabel.Alignment = d2gui.HorizontalAlignCenter
return &Inventory{
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
asset: asset,
uiManager: ui,
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
grid: NewItemGrid(asset, ui, record),
originX: record.Panel.Left,
hoverLabel: hoverLabel,
// originY: record.Panel.Top,
originY: 0, // expansion data has these all offset by +60 ...
}
}
2020-08-11 22:01:33 +00:00
// IsOpen returns true if the inventory is open
func (g *Inventory) IsOpen() bool {
return g.isOpen
}
2020-08-11 22:01:33 +00:00
// Toggle negates the open state of the inventory
func (g *Inventory) Toggle() {
g.isOpen = !g.isOpen
}
2020-08-11 22:01:33 +00:00
// Open opens the inventory
func (g *Inventory) Open() {
g.isOpen = true
}
2020-08-11 22:01:33 +00:00
// Close closes the inventory
func (g *Inventory) Close() {
g.isOpen = false
}
// Load the resources required by the inventory
func (g *Inventory) Load() {
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
animation, _ := g.asset.LoadAnimation(d2resource.Frame, d2resource.PaletteSky)
g.frame, _ = g.uiManager.NewSprite(animation)
remove d2asset singleton (#726) * export d2asset singleton * add *d2asset.AssetManager to d2app - d2app now has a reference to an asset manager which it will use for loading - added asset loader methods to the asset manager - functions in d2asset are now wrappers for asset manager methods * add asset manager reference to audio provider - d2app asset manager reference is now passed to audio provider - asset manager is created in main.go for now to pass into audio provider - CreateSoundEffect is now a method, no longer exported, uses the asset manager reference * d2app passes asset manager refence to map engine test * in d2asset, all calls to LoadFile replaced with call to Singleton.Loadfile * blizzard intro and credits screen - d2app passes reference to the asset manager to these screens * asset manager for d2map - adding MapStampFactory, takes an asset manager reference - embedded MapStampFactory into the MapEngine - LoadStamp is now a method of the MapStampFactory * d2asset: removed LoadFileStream, LoadFile, and FileExists * d2gui changes - singleton now has an asset manager reference - calls to d2asset loader functions removed - createButton is now a method of LayoutManager - moved LayoutEntry to its own file * map entity factory - Map engine has an embedded map entity factory - Map stamp factory gets a reference to the map engine's entity factory - Stamps are given a reference to the map engine entity factory when created - Character select gets a map entity factory - Embedded the stamp factory into the MapEngine * asset manager for d2ui - d2ui is passed an asset manager reference when created - all calls to d2asset loader functions in d2ui now refer to the asset manager - d2gamescreen gets a ui manager when created - help overlay is now passed a ui manager when created * d2gamescreen + d2player: asset manager references added an asset manager reference to - inventory panel + inventory grid - mini panel - game controls - help overlay - character select - main menu - select hero class - hero stats panel * Removed d2asset.LoadAnimation all references to this function have been replaced with calls to the asset manager method * adding asset to help overlay, bugfix for 4d59c91 * Removed d2asset.LoadFont and d2asset.LoadAnimationWithEffect all references to these have been replaced with calls to the asset manager methods * MapRenderer now gets an asset manager reference * removed d2asset.LoadPalette all references have been replaced with calls to an asset manager instance * merged d2object with d2mapentity d2object was only being used to create objects in the map, so the provider function is now a method of the map entity factory. calls to d2asset have been removed. * removed d2asset.LoadComposite all calls are now made to the asset manager method * removed d2asset singleton all singleton references have been removed, a single instance of the asset manager is passed around the entire app * rename Initialize to NewAssetManager
2020-09-12 20:51:30 +00:00
animation, _ = g.asset.LoadAnimation(d2resource.InventoryCharacterPanel, d2resource.PaletteSky)
g.panel, _ = g.uiManager.NewSprite(animation)
items := []InventoryItem{
diablo2item.NewItem("kit", "Crimson", "of the Bat", "of Frost").Identify(),
diablo2item.NewItem("rin", "Steel", "of Shock").Identify(),
diablo2item.NewItem("jav").Identify(),
diablo2item.NewItem("buc").Identify(),
2020-08-11 22:01:33 +00:00
// diablo2item.NewItem("Arctic Furs", "qui"),
// TODO: Load the player's actual items
}
2020-08-11 22:01:33 +00:00
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotLeftArm, diablo2item.NewItem("wnd"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotRightArm, diablo2item.NewItem("buc"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotHead, diablo2item.NewItem("crn"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotTorso, diablo2item.NewItem("plt"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotLegs, diablo2item.NewItem("vbt"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotBelt, diablo2item.NewItem("vbl"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotGloves, diablo2item.NewItem("lgl"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotLeftHand, diablo2item.NewItem("rin"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotRightHand, diablo2item.NewItem("rin"))
g.grid.ChangeEquippedSlot(d2enum.EquippedSlotNeck, diablo2item.NewItem("amu"))
// TODO: Load the player's actual items
2020-08-11 22:01:33 +00:00
_, err := g.grid.Add(items...)
if err != nil {
fmt.Printf("could not add items to the inventory, err: %v\n", err)
}
}
2020-08-11 22:01:33 +00:00
// Render draws the inventory onto the given surface
2020-07-26 18:52:54 +00:00
func (g *Inventory) Render(target d2interface.Surface) error {
if !g.isOpen {
2020-07-26 18:52:54 +00:00
return nil
}
x, y := g.originX, g.originY
// Frame
// Top left
2020-07-26 18:52:54 +00:00
if err := g.frame.SetCurrentFrame(5); err != nil {
return err
}
w, h := g.frame.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.frame.SetPosition(x, y+h)
2020-07-26 18:52:54 +00:00
if err := g.frame.Render(target); err != nil {
return err
}
x += w
// Top right
2020-07-26 18:52:54 +00:00
if err := g.frame.SetCurrentFrame(6); err != nil {
return err
}
w, h = g.frame.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.frame.SetPosition(x, y+h)
2020-07-26 18:52:54 +00:00
if err := g.frame.Render(target); err != nil {
return err
}
x += w
y += h
// Right
2020-07-26 18:52:54 +00:00
if err := g.frame.SetCurrentFrame(7); err != nil {
return err
}
w, h = g.frame.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.frame.SetPosition(x-w, y+h)
2020-07-26 18:52:54 +00:00
if err := g.frame.Render(target); err != nil {
return err
}
y += h
// Bottom right
2020-07-26 18:52:54 +00:00
if err := g.frame.SetCurrentFrame(8); err != nil {
return err
}
w, h = g.frame.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.frame.SetPosition(x-w, y+h)
2020-07-26 18:52:54 +00:00
if err := g.frame.Render(target); err != nil {
return err
}
x -= w
// Bottom left
2020-07-26 18:52:54 +00:00
if err := g.frame.SetCurrentFrame(9); err != nil {
return err
}
w, h = g.frame.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.frame.SetPosition(x-w, y+h)
2020-07-26 18:52:54 +00:00
if err := g.frame.Render(target); err != nil {
return err
}
x, y = g.originX+1, g.originY
y += 64
// Panel
// Top left
2020-07-26 18:52:54 +00:00
if err := g.panel.SetCurrentFrame(4); err != nil {
return err
}
w, h = g.panel.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.panel.SetPosition(x, y+h)
2020-07-26 18:52:54 +00:00
if err := g.panel.Render(target); err != nil {
return err
}
x += w
// Top right
2020-07-26 18:52:54 +00:00
if err := g.panel.SetCurrentFrame(5); err != nil {
return err
}
2020-08-11 22:01:33 +00:00
_, h = g.panel.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.panel.SetPosition(x, y+h)
2020-07-26 18:52:54 +00:00
if err := g.panel.Render(target); err != nil {
return err
}
y += h
// Bottom right
2020-07-26 18:52:54 +00:00
if err := g.panel.SetCurrentFrame(7); err != nil {
return err
}
2020-08-11 22:01:33 +00:00
_, h = g.panel.GetCurrentFrameSize()
g.panel.SetPosition(x, y+h)
2020-07-26 18:52:54 +00:00
if err := g.panel.Render(target); err != nil {
return err
}
// Bottom left
2020-07-26 18:52:54 +00:00
if err := g.panel.SetCurrentFrame(6); err != nil {
return err
}
w, h = g.panel.GetCurrentFrameSize()
2020-07-26 18:52:54 +00:00
g.panel.SetPosition(x-w, y+h)
2020-07-26 18:52:54 +00:00
if err := g.panel.Render(target); err != nil {
return err
}
g.grid.Render(target)
2020-07-26 18:52:54 +00:00
hovering := false
for idx := range g.grid.items {
item := g.grid.items[idx]
ix, iy := g.grid.SlotToScreen(item.InventoryGridSlot())
iw, ih := g.grid.sprites[item.GetItemCode()].GetCurrentFrameSize()
mx, my := g.lastMouseX, g.lastMouseY
hovering = hovering || ((mx > ix) && (mx < ix+iw) && (my > iy) && (my < iy+ih))
if hovering {
if !g.hovering {
// set the initial hover coordinates
// this is so that moving mouse doesnt move the description
g.hoverX, g.hoverY = mx, my
}
g.renderItemDescription(target, item)
break
}
}
g.hovering = hovering
2020-07-26 18:52:54 +00:00
return nil
}
func (g *Inventory) renderItemDescription(target d2interface.Surface, i InventoryItem) {
lines := i.GetItemDescription()
maxW, maxH := 0, 0
_, iy := g.grid.SlotToScreen(i.InventoryGridSlot())
for idx := range lines {
w, h := g.hoverLabel.GetTextMetrics(lines[idx])
if maxW < w {
maxW = w
}
maxH += h
}
halfW, halfH := maxW/2, maxH/2
centerX, centerY := g.hoverX, iy-halfH
if (centerX + halfW) > 800 {
centerX = 800 - halfW
}
if (centerY + halfH) > 600 {
centerY = 600 - halfH
}
target.PushTranslation(centerX, centerY)
target.PushTranslation(-halfW, -halfH)
target.DrawRect(maxW, maxH, color.RGBA{0, 0, 0, uint8(200)})
target.PushTranslation(halfW, 0)
for idx := range lines {
g.hoverLabel.SetText(lines[idx])
_, h := g.hoverLabel.GetTextMetrics(lines[idx])
g.hoverLabel.Render(target)
target.PushTranslation(0, h)
}
target.PopN(len(lines))
target.PopN(3)
}