112 lines
3.1 KiB
Go
112 lines
3.1 KiB
Go
package mesh
|
||
|
||
import (
|
||
"path/filepath"
|
||
"testing"
|
||
|
||
"mc/internal/block"
|
||
"mc/internal/chunk"
|
||
)
|
||
|
||
// loadReg 加载注册表。
|
||
func loadReg(t *testing.T) *block.Registry {
|
||
t.Helper()
|
||
r, err := block.Load(filepath.Join("..", "..", "assets", "config", "blocks.json"))
|
||
if err != nil {
|
||
t.Fatalf("加载注册表失败: %v", err)
|
||
}
|
||
return r
|
||
}
|
||
|
||
// airNb 邻居查询:全部视为空气(不剔除任何面)。
|
||
func airNb(x, y, z int32) block.State { return block.Air }
|
||
|
||
// dummyUV 固定 UV(测试不关心贴图坐标)。
|
||
func dummyUV(key string) (float32, float32, float32, float32, bool) {
|
||
return 0, 0, 1, 1, true
|
||
}
|
||
|
||
// TestPoolReuse 顶点池复用:Build → Release → 再次 Build 不崩溃且结果正确(性能与内存.md §2)。
|
||
func TestPoolReuse(t *testing.T) {
|
||
reg := loadReg(t)
|
||
stone, _ := reg.ID("stone")
|
||
c := chunk.New(0, 0)
|
||
c.Fill(0, 0, 0, block.NewState(stone, 0))
|
||
b := NewBuilder(reg, dummyUV)
|
||
for i := 0; i < 3; i++ {
|
||
m := b.Build(c, airNb)
|
||
if len(m.Opaque) != 24 {
|
||
t.Fatalf("第 %d 次构建顶点数异常: %d", i, len(m.Opaque))
|
||
}
|
||
Release(m)
|
||
}
|
||
}
|
||
|
||
// TestSingleBlock 单方块 6 面全生成:24 顶点(6 面 × 4 顶点四边形)。
|
||
func TestSingleBlock(t *testing.T) {
|
||
reg := loadReg(t)
|
||
stone, _ := reg.ID("stone")
|
||
c := chunk.New(0, 0)
|
||
c.Fill(0, 0, 0, block.NewState(stone, 0))
|
||
c.SetBlockLight(0, 0, 0, 10)
|
||
|
||
b := NewBuilder(reg, dummyUV)
|
||
m := b.Build(c, airNb)
|
||
if len(m.Opaque) != 24 {
|
||
t.Fatalf("不透明顶点期望 24,实际 %d", len(m.Opaque))
|
||
}
|
||
if len(m.Cutout) != 0 || len(m.Translucent) != 0 {
|
||
t.Fatalf("其他通道应为空: cutout=%d translucent=%d", len(m.Cutout), len(m.Translucent))
|
||
}
|
||
// 顶点光照传递
|
||
for _, v := range m.Opaque {
|
||
if v.Block != 10 {
|
||
t.Fatalf("顶点方块光期望 10,实际 %d", v.Block)
|
||
}
|
||
}
|
||
}
|
||
|
||
// TestFaceCulling 相邻不透明方块剔除共享面:2 块相邻 → 各 5 面 → 40 顶点。
|
||
func TestFaceCulling(t *testing.T) {
|
||
reg := loadReg(t)
|
||
stone, _ := reg.ID("stone")
|
||
c := chunk.New(0, 0)
|
||
c.Fill(0, 0, 0, block.NewState(stone, 0))
|
||
c.Fill(1, 0, 0, block.NewState(stone, 0))
|
||
|
||
// 邻居查询:跨区块查空气,区块内查实际方块
|
||
nb := func(x, y, z int32) block.State {
|
||
if x < 0 || x >= 16 || y < 0 || y >= chunk.Height || z < 0 || z >= 16 {
|
||
return block.Air
|
||
}
|
||
return c.Block(int(x), int(y), int(z))
|
||
}
|
||
b := NewBuilder(reg, dummyUV)
|
||
m := b.Build(c, nb)
|
||
if len(m.Opaque) != 40 {
|
||
t.Fatalf("面剔除后顶点期望 40,实际 %d", len(m.Opaque))
|
||
}
|
||
}
|
||
|
||
// TestChannels 透明分类:火把→cutout,水→translucent(渲染.md §6)。
|
||
func TestChannels(t *testing.T) {
|
||
reg := loadReg(t)
|
||
torch, _ := reg.ID("torch")
|
||
water, _ := reg.ID("water")
|
||
c := chunk.New(0, 0)
|
||
c.Fill(0, 0, 0, block.NewState(torch, 0))
|
||
c.Fill(2, 0, 0, block.NewState(water, 0))
|
||
|
||
b := NewBuilder(reg, dummyUV)
|
||
m := b.Build(c, airNb)
|
||
if len(m.Cutout) != 24 {
|
||
t.Fatalf("火把 cutout 顶点期望 24,实际 %d", len(m.Cutout))
|
||
}
|
||
if len(m.Translucent) != 24 {
|
||
t.Fatalf("水 translucent 顶点期望 24,实际 %d", len(m.Translucent))
|
||
}
|
||
if len(m.Opaque) != 0 {
|
||
t.Fatalf("不应有不透明顶点,实际 %d", len(m.Opaque))
|
||
}
|
||
}
|