Files
ngzz-mc/internal/ui/inventory.go
2026-09-19 14:21:08 +08:00

156 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build gl
// 物品栏界面UI还原.md §3.3、物品与背包.md §3
// inventory.png 176×166 + 27 主区 (7,83) + 热键栏 (7,141) + 盔甲 4 (7,8)
// + 副手 (77,8) + 2×2 (98,8) + 输出 (125,24) + 玩家模型 (34,9)(69,80)。
package ui
import (
"fmt"
"mc/internal/item"
)
// InventoryScreen 物品栏界面。
type InventoryScreen struct {
itemIcons
bgTex uint32
winW, winH float32
tipTex uint32
tipW, tipH float32
OpenT float32
}
// NewInventoryScreen 创建物品栏界面。
func NewInventoryScreen(bgTex uint32, items *item.Registry) *InventoryScreen {
s := &InventoryScreen{bgTex: bgTex, winW: 176, winH: 166, OpenT: 1}
s.items = items
s.itemUV = map[string][4]float32{}
s.blockUV = map[string][4]float32{}
return s
}
// SetItemAtlas 设置 items 图集。
func (s *InventoryScreen) SetItemAtlas(tex uint32, uv map[string][4]float32) {
s.setItemAtlas(tex, uv)
}
// SetBlockAtlas 设置 blocks 图集。
func (s *InventoryScreen) SetBlockAtlas(tex uint32, uv map[string][4]float32) {
s.setBlockAtlas(tex, uv)
}
// SetTooltip 设置悬停名称纹理tick 光栅化 CJK渲染线程上传
func (s *InventoryScreen) SetTooltip(tex uint32, w, h float32) {
s.tipTex = tex
s.tipW, s.tipH = w, h
}
// HitTest 命中main026 / hot08 / armor03 / offhand / craft03 / result。
func (s *InventoryScreen) HitTest(mx, my float32, screenW, screenH, scale float32) string {
bx, by := screenW/2-s.winW/2*scale, screenH/2-s.winH/2*scale
for i := 0; i < 4; i++ {
if hitSlot(mx, my, bx, by, 7, 8+float32(i)*18, scale) {
return "armor" + fmt.Sprintf("%d", i)
}
}
if hitSlot(mx, my, bx, by, 77, 8, scale) {
return "offhand"
}
for i := 0; i < 4; i++ {
px := 98 + float32(i%2)*18
py := 8 + float32(i/2)*18
if hitSlot(mx, my, bx, by, px, py, scale) {
return "craft" + fmt.Sprintf("%d", i)
}
}
if hitSlot(mx, my, bx, by, 125, 24, scale) {
return "result"
}
for i := 0; i < 27; i++ {
px := 7 + float32(i%9)*18
py := 83 + float32(i/9)*18
if hitSlot(mx, my, bx, by, px, py, scale) {
return "main" + fmt.Sprintf("%d", i)
}
}
for i := 0; i < 9; i++ {
if hitSlot(mx, my, bx, by, 7+float32(i)*18, 141, scale) {
return "hot" + fmt.Sprintf("%d", i)
}
}
return ""
}
// Draw 绘制物品栏slots 含盔甲/副手craft 为 2×2res 为输出)。
func (s *InventoryScreen) Draw(r *Renderer, slots []item.Stack, craft [4]item.Stack, res item.Stack, hasRes bool, held item.Stack, mx, my, scale float32) {
w, h := float32(r.w), float32(r.h)
r.DrawRect(0, 0, w, h, [4]float32{0, 0, 0, 0.35})
sc := scale * (0.85 + 0.15*s.OpenT)
bx, by := w/2-s.winW/2*sc, h/2-s.winH/2*sc
if s.bgTex != 0 {
r.pushQuad(quad{x: bx, y: by, w: s.winW * sc, h: s.winH * sc,
u0: 0, v0: 0, u1: 176.0 / 256.0, v1: 166.0 / 256.0,
r: 1, g: 1, b: 1, a: 1, tex: s.bgTex})
}
s.drawPlayerModel(r, bx, by, sc)
// 盔甲 4
for i := 0; i < 4; i++ {
idx := 36 + i
st := item.Stack{}
if idx < len(slots) {
st = slots[idx]
}
s.drawSlot(r, st, bx+(7+1)*sc, by+(8+float32(i)*18+1)*sc, sc)
}
if 40 < len(slots) {
s.drawSlot(r, slots[40], bx+(77+1)*sc, by+(8+1)*sc, sc)
}
for i := 0; i < 4; i++ {
px := 98 + float32(i%2)*18
py := 8 + float32(i/2)*18
s.drawSlot(r, craft[i], bx+(px+1)*sc, by+(py+1)*sc, sc)
}
if hasRes {
s.drawSlot(r, res, bx+(125+1)*sc, by+(24+1)*sc, sc)
}
for i := 0; i < 27; i++ {
idx := 9 + i
st := item.Stack{}
if idx < len(slots) {
st = slots[idx]
}
px := 7 + float32(i%9)*18
py := 83 + float32(i/9)*18
s.drawSlot(r, st, bx+(px+1)*sc, by+(py+1)*sc, sc)
}
for i := 0; i < 9 && i < len(slots); i++ {
s.drawSlot(r, slots[i], bx+(7+float32(i)*18+1)*sc, by+(141+1)*sc, sc)
}
if !held.Empty() {
s.drawSlot(r, held, mx-8*scale, my-8*scale, scale)
}
if s.tipTex != 0 && s.tipW > 0 {
tx, ty := mx+12, my+12
drawTooltipBG(r, tx, ty, s.tipW, s.tipH)
r.pushQuad(quad{x: tx, y: ty, w: s.tipW, h: s.tipH,
u0: 0, v0: 0, u1: 1, v1: 1, r: 1, g: 1, b: 1, a: 1, tex: s.tipTex})
}
}
func (s *InventoryScreen) drawPlayerModel(r *Renderer, bx, by, scale float32) {
// 简化纸片人,区域 (34,9)(69,80)
ox, oy := bx+34*scale, by+9*scale
skin := [4]float32{0.85, 0.68, 0.52, 1}
shirt := [4]float32{0.25, 0.35, 0.75, 1}
pants := [4]float32{0.22, 0.22, 0.55, 1}
// 头 8×8、身 8×12、臂 4×12、腿 4×12逻辑像素
r.DrawRect(ox+10*scale, oy+2*scale, 8*scale, 8*scale, skin)
r.DrawRect(ox+10*scale, oy+10*scale, 8*scale, 12*scale, shirt)
r.DrawRect(ox+6*scale, oy+10*scale, 4*scale, 12*scale, shirt)
r.DrawRect(ox+18*scale, oy+10*scale, 4*scale, 12*scale, shirt)
r.DrawRect(ox+10*scale, oy+22*scale, 4*scale, 12*scale, pants)
r.DrawRect(ox+14*scale, oy+22*scale, 4*scale, 12*scale, pants)
}