Files
aego/render/mesh/batcher.go
T
sanspie 5eb1832907
ci-platforms / darwin amd64 smoke (push) Skipped
ci / build (amd64, linux, ubuntu-24.04) (push) Failing after 15m28s
ci / release (push) Skipped
ci-platforms / windows amd64 smoke (push) Skipped
ci-platforms / darwin arm64 smoke (push) Skipped
ci / checks (push) Successful in 7m47s
Complete Stage 12 for v0.12.0
2026-11-05 11:46:53 +03:00

187 lines
3.5 KiB
Go

package mesh
import (
"slices"
"aego/core/mathx"
"aego/gpu"
"aego/render/material"
"aego/render/sprite"
"aego/render/texture"
)
type Draw struct {
VisibilityLayers uint64
LightSet uint32
Normal texture.Region
Emission texture.Emission
Mesh *Mesh
World mathx.Mat4
Texture texture.Region
Sampler gpu.SamplerHandle
Color mathx.Color
Blend sprite.BlendMode
DoubleSided bool
Layer int16
Order int16
Z float32
Is2D bool
Material *material.Material
Lanes *[16]float32
}
type Item struct {
Draw
Dist float32
Key uint64
}
type Batcher struct {
max int
opaque []Item
blend []Item
twoD []Item
dropped uint32
}
func NewBatcher(maxDraws int) *Batcher {
if maxDraws < 1 {
maxDraws = 1
}
return &Batcher{
max: maxDraws,
opaque: make([]Item, 0, maxDraws),
blend: make([]Item, 0, maxDraws),
twoD: make([]Item, 0, maxDraws),
}
}
func (b *Batcher) Reset() {
b.opaque = b.opaque[:0]
b.blend = b.blend[:0]
b.twoD = b.twoD[:0]
b.dropped = 0
}
func (b *Batcher) Len() int {
return len(b.opaque) + len(b.blend) + len(b.twoD)
}
func (b *Batcher) Dropped() uint32 {
return b.dropped
}
func (b *Batcher) Push(d *Draw, cam mathx.Vec3, white texture.Region, sampler gpu.SamplerHandle) bool {
return b.PushOrdered(d, cam, white, sampler, 0, 0, 1)
}
func (b *Batcher) PushOrdered(d *Draw, cam mathx.Vec3, white texture.Region, sampler gpu.SamplerHandle, sequence uint32, zMin, zMax float32) bool {
if d.Mesh == nil {
return false
}
if b.Len() >= b.max {
b.dropped++
return false
}
it := Item{Draw: *d}
if it.Material != nil {
it.Blend = sprite.BlendMode(it.Material.Blend())
}
if it.Texture.IsZero() {
it.Texture = white
}
if it.Sampler.IsZero() {
it.Sampler = sampler
}
it.Dist = d.World.TransformPoint(d.Mesh.Bounds.Center()).Sub(cam).LenSq()
if it.Is2D {
it.Key = uint64(sprite.MakeKey(it.Layer, it.Order, it.Z, zMin, zMax, sequence))
b.twoD = append(b.twoD, it)
} else if it.Blend == sprite.BlendOpaque {
b.opaque = append(b.opaque, it)
} else {
b.blend = append(b.blend, it)
}
return true
}
func cmpDist(a, b float32) int {
switch {
case a < b:
return -1
case a > b:
return 1
}
return 0
}
func cmpOpaque(a, b Item) int {
if a.Is2D || b.Is2D {
return cmp2D(a, b)
}
if a.DoubleSided != b.DoubleSided {
if !a.DoubleSided {
return -1
}
return 1
}
ta, tb := a.Texture.Texture, b.Texture.Texture
if ta.Index != tb.Index {
return int(ta.Index) - int(tb.Index)
}
if ta.Gen != tb.Gen {
return int(ta.Gen) - int(tb.Gen)
}
return cmpDist(a.Dist, b.Dist)
}
func cmpBlend(a, b Item) int {
if a.Is2D || b.Is2D {
return cmp2D(a, b)
}
if a.Layer != b.Layer {
return int(a.Layer) - int(b.Layer)
}
return cmpDist(b.Dist, a.Dist)
}
func (b *Batcher) Sort() {
slices.SortStableFunc(b.opaque, cmpOpaque)
slices.SortStableFunc(b.blend, cmpBlend)
slices.SortStableFunc(b.twoD, func(a, b Item) int {
if a.Key < b.Key {
return -1
}
if a.Key > b.Key {
return 1
}
return 0
})
}
func (b *Batcher) Opaque() []Item {
return b.opaque
}
func (b *Batcher) Transparent() []Item {
return b.blend
}
func cmp2D(a, b Item) int {
if a.Is2D != b.Is2D {
if a.Is2D {
return 1
}
return -1
}
if a.Layer != b.Layer {
return int(a.Layer) - int(b.Layer)
}
if a.Order != b.Order {
return int(a.Order) - int(b.Order)
}
return cmpDist(a.Z, b.Z)
}
func (b *Batcher) TwoD() []Item { return b.twoD }