Files
ngzz-mc/internal/textr/text.go

80 lines
1.9 KiB
Go
Raw Normal View History

// Package textr 文本光栅化:把字符串用位图字体渲染成 RGBA 图像(CPU 侧,UI还原.md §4)。
//
// 字形来自素材包 8×8 位图字体(internal/font);本包输出可直接上传为 GL 纹理的图像,
// 因此与渲染线程解耦(GL 只负责贴图)。
package textr
import (
"image"
"image/color"
"image/draw"
"mc/internal/font"
)
// Drawer 文本绘制器。
type Drawer struct {
atlas *font.Atlas
}
// New 创建绘制器。
func New(atlas *font.Atlas) *Drawer { return &Drawer{atlas: atlas} }
// Width 计算文本像素宽度(8px/字符)。
func (d *Drawer) Width(s string) int {
w := 0
for _, r := range s {
if g, ok := d.atlas.Glyphs[r]; ok {
w += g.Width
} else {
w += 8 // 缺失字形占位
}
}
return w
}
// Draw 渲染一行文本(白字透明底;shadow 为 true 时附加 1px 黑色阴影,UI还原.md §4)。
// 返回图像与阴影偏移(阴影在图像内左上角,调用方绘制时需偏移 1px)。
func (d *Drawer) Draw(s string, c color.RGBA, shadow bool) image.Image {
w := d.Width(s)
h := 8
if shadow {
w++
h++
}
img := image.NewRGBA(image.Rect(0, 0, w, h))
x := 0
for _, r := range s {
g, ok := d.atlas.Glyphs[r]
if !ok {
g = d.atlas.Missing()
}
d.blit(img, g, x, 0, c)
if shadow {
d.blit(img, g, x+1, 1, color.RGBA{0, 0, 0, 255})
}
x += g.Width
}
return img
}
// blit 把字形像素以指定颜色写入目标(字形位图按 alpha 通道着色)。
func (d *Drawer) blit(dst *image.RGBA, g font.Glyph, dx, dy int, c color.RGBA) {
if d.atlas.Image == nil {
return
}
src := d.atlas.Image
for y := 0; y < g.H; y++ {
for x := 0; x < g.W; x++ {
r, _, _, a := src.At(g.X+x, g.Y+y).RGBA()
if a == 0 {
continue
}
_ = r // 字形颜色以纹理亮度为准,目标色统一用 c
dst.SetRGBA(dx+x, dy+y, c)
}
}
}
var _ = draw.Draw // 保持 image/draw 引用(后续 9-patch 使用)