//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 命中:main0–26 / hot0–8 / armor0–3 / offhand / craft0–3 / 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×2;res 为输出)。 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) }