Files
ngzz-mc/cmd/client/screens_gl.go

140 lines
4.1 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 §2)——土质背景、原版按钮控件、
// 中文标题「年糕历险记」、黄色 splash、版本/版权角标。
package main
import (
"image"
"image/color"
"image/draw"
"image/png"
"os"
"path/filepath"
"mc/internal/assets"
"mc/internal/cjkfont"
"mc/internal/ui"
)
// cjkPaths 系统 CJK 字体候选。
var cjkPaths = []string{
filepath.Join(os.Getenv("WINDIR"), "Fonts", "msyh.ttc"),
filepath.Join(os.Getenv("WINDIR"), "Fonts", "msyh.ttf"),
}
// loadCJK 加载系统 CJK 字体(失败返回 nil → 中文标签退化不显示)。
func loadCJK() *cjkfont.Renderer {
for _, p := range cjkPaths {
if _, err := os.Stat(p); err == nil {
if r, err := cjkfont.Load(p, 24); err == nil {
return r
}
}
}
return nil
}
// buildScreens 构建主菜单与暂停菜单(原版布局与控件)。
func buildScreens(r *ui.Renderer, am *assets.Manager, lang *assets.Lang) (*ui.TitleScreen, *ui.PauseScreen) {
cjk := loadCJK()
// 原版按钮控件(widget/button.png 200×20 与悬停高亮)
loadPng := func(key string) (uint32, bool) {
p, ok := am.ResolveTexture(key)
if !ok {
return 0, false
}
f, err := os.Open(p)
if err != nil {
return 0, false
}
img, err := png.Decode(f)
_ = f.Close()
if err != nil {
return 0, false
}
return r.UploadImage(img), true
}
btnTex, _ := loadPng("gui/sprites/widget/button")
btnHover, _ := loadPng("gui/sprites/widget/button_highlighted")
// 土质背景:16px dirt 平铺 1280×720(原版菜单背景质感)
bgTex := tileBackground(r, am)
// 中文文本光栅化
text := func(s string, size float64, c color.RGBA) (uint32, float32, float32) {
if cjk == nil || s == "" {
return 0, 0, 0
}
img := cjk.Draw(s, c)
return r.UploadImage(img), float32(img.Bounds().Dx()), float32(img.Bounds().Dy())
}
tr := func(key, fallback string, size float64, c color.RGBA) (uint32, float32, float32) {
s := fallback
if lang != nil && lang.Get(key) != key {
s = lang.Get(key)
}
return text(s, size, c)
}
// 标题与 splash(原版:大标题 + 黄色 splash 于其右下)
titleTex, tw, th := tr("menu.title", "年糕历险记", 96, color.RGBA{255, 255, 255, 255})
splashTex, sw, sh := tr("menu.splash", "牛气冲天!", 24, color.RGBA{255, 255, 85, 255})
// 按钮(原版 200×20、间距 24、居中,UI还原.md §2 布局)
mkBtn := func(key, fallback, action string, y float32) ui.Button {
tex, lw, lh := tr(key, fallback, 18, color.RGBA{255, 255, 255, 255})
return ui.Button{X: 1280/2 - 100, Y: y, W: 200, H: 20, Tex: tex, LabelW: lw, LabelH: lh, Action: action}
}
title := &ui.TitleScreen{
TitleTex: titleTex, TitleW: tw, TitleH: th,
SplashTex: splashTex, SplashW: sw, SplashH: sh,
BgTex: bgTex, BtnTex: btnTex, BtnHover: btnHover,
Version: "年糕历险记 v0.1.0",
Copyright: "Copyright NianGao Studio. 请勿分发!",
}
title.Buttons = []ui.Button{
mkBtn("menu.singleplayer", "单人游戏", "play", 390),
mkBtn("menu.multiplayer", "多人游戏", "multi", 414),
mkBtn("menu.options", "设置…", "", 438),
mkBtn("menu.quit", "退出游戏", "quit", 462),
}
pauseTitle, ptw, pth := tr("menu.game", "游戏菜单", 32, color.RGBA{255, 255, 255, 255})
pause := &ui.PauseScreen{
TitleTex: pauseTitle, TitleW: ptw, TitleH: pth,
BtnTex: btnTex, BtnHover: btnHover,
}
pause.Buttons = []ui.Button{
mkBtn("gui.resume", "继续游戏", "resume", 300),
mkBtn("menu.quit", "保存并退出", "quit", 324),
}
return title, pause
}
// tileBackground 把 dirt 纹理平铺成全屏背景(像素风土墙)。
func tileBackground(r *ui.Renderer, am *assets.Manager) uint32 {
p, ok := am.ResolveTexture("block/dirt")
if !ok {
return 0
}
f, err := os.Open(p)
if err != nil {
return 0
}
tile, err := png.Decode(f)
_ = f.Close()
if err != nil {
return 0
}
const w, h = 1280, 720
bg := image.NewRGBA(image.Rect(0, 0, w, h))
for y := 0; y < h; y += 16 {
for x := 0; x < w; x += 16 {
draw.Draw(bg, image.Rect(x, y, x+16, y+16), tile, image.Point{}, draw.Src)
}
}
return r.UploadImage(bg)
}