WIP: drawDAG working
This commit is contained in:
parent
89febffcea
commit
f1adaead81
6 changed files with 67 additions and 13 deletions
|
@ -1,7 +1,9 @@
|
||||||
package engine
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"drjosh.dev/gurgle/geom"
|
"drjosh.dev/gurgle/geom"
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
@ -17,6 +19,7 @@ type DrawDAG struct {
|
||||||
Hides
|
Hides
|
||||||
|
|
||||||
*dag
|
*dag
|
||||||
|
boxCache map[DrawBoxer]geom.Box
|
||||||
chunks map[image.Point]drawerSet // chunk coord -> drawers with bounding rects intersecting chunk
|
chunks map[image.Point]drawerSet // chunk coord -> drawers with bounding rects intersecting chunk
|
||||||
chunksRev map[DrawBoxer]image.Rectangle // comopnent -> rectangle of chunk coords
|
chunksRev map[DrawBoxer]image.Rectangle // comopnent -> rectangle of chunk coords
|
||||||
parent func(x interface{}) interface{}
|
parent func(x interface{}) interface{}
|
||||||
|
@ -88,15 +91,18 @@ func (d *DrawDAG) DrawAll(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
||||||
|
|
||||||
func (d *DrawDAG) Prepare(game *Game) error {
|
func (d *DrawDAG) Prepare(game *Game) error {
|
||||||
d.dag = newDAG()
|
d.dag = newDAG()
|
||||||
|
d.boxCache = make(map[DrawBoxer]geom.Box)
|
||||||
d.chunks = make(map[image.Point]drawerSet)
|
d.chunks = make(map[image.Point]drawerSet)
|
||||||
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
d.chunksRev = make(map[DrawBoxer]image.Rectangle)
|
||||||
d.parent = game.Parent
|
d.parent = game.Parent
|
||||||
d.proj = game.Projection
|
d.proj = game.Projection
|
||||||
|
|
||||||
// Load all descendants into the DAG
|
// Descendants might not be prepared yet, so fill the cache with zero boxes
|
||||||
|
// and fill remaining data structures during update
|
||||||
|
// TODO: work out a system for dependent prepares........ sync.Once?
|
||||||
return PreorderWalk(d, func(c, _ interface{}) error {
|
return PreorderWalk(d, func(c, _ interface{}) error {
|
||||||
if db, ok := c.(DrawBoxer); ok {
|
if db, ok := c.(DrawBoxer); ok {
|
||||||
d.Add(db)
|
d.boxCache[db] = geom.Box{}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
@ -104,16 +110,39 @@ func (d *DrawDAG) Prepare(game *Game) error {
|
||||||
|
|
||||||
func (d *DrawDAG) Scan() []interface{} { return d.Components }
|
func (d *DrawDAG) Scan() []interface{} { return d.Components }
|
||||||
|
|
||||||
|
func (d *DrawDAG) Update() error {
|
||||||
|
// Re-evaluate bounding boxes for all descendants. If a box has changed,
|
||||||
|
// fix up the edges by removing and re-adding the vertex.
|
||||||
|
var readd []DrawBoxer
|
||||||
|
for db, bb := range d.boxCache {
|
||||||
|
nbb := db.BoundingBox()
|
||||||
|
if bb != nbb {
|
||||||
|
d.Remove(db)
|
||||||
|
readd = append(readd, db)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, db := range readd {
|
||||||
|
d.Add(db)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Add adds a Drawer and any needed edges to the DAG and chunk map.
|
// Add adds a Drawer and any needed edges to the DAG and chunk map.
|
||||||
func (d *DrawDAG) Add(x DrawBoxer) {
|
func (d *DrawDAG) Add(x DrawBoxer) {
|
||||||
πsign := d.proj.Sign()
|
πsign := d.proj.Sign()
|
||||||
br := x.BoundingBox().BoundingRect(d.proj)
|
|
||||||
|
// Update the box cache
|
||||||
|
bb := x.BoundingBox()
|
||||||
|
d.boxCache[x] = bb
|
||||||
|
|
||||||
// Update the reverse chunk map
|
// Update the reverse chunk map
|
||||||
|
br := bb.BoundingRect(d.proj)
|
||||||
revr := image.Rectangle{
|
revr := image.Rectangle{
|
||||||
Min: br.Min.Div(d.ChunkSize),
|
Min: br.Min.Div(d.ChunkSize),
|
||||||
Max: br.Max.Sub(image.Pt(1, 1)).Div(d.ChunkSize),
|
Max: br.Max.Sub(image.Pt(1, 1)).Div(d.ChunkSize),
|
||||||
}
|
}
|
||||||
d.chunksRev[x] = revr
|
d.chunksRev[x] = revr
|
||||||
|
|
||||||
// Find possible edges between x and items in the overlapping cells.
|
// Find possible edges between x and items in the overlapping cells.
|
||||||
// First, a set of all the items in those cells.
|
// First, a set of all the items in those cells.
|
||||||
cand := make(drawerSet)
|
cand := make(drawerSet)
|
||||||
|
@ -208,19 +237,42 @@ func drawOrderConstraint(u, v DrawBoxer, πsign image.Point) bool {
|
||||||
|
|
||||||
type drawerSet map[Drawer]struct{}
|
type drawerSet map[Drawer]struct{}
|
||||||
|
|
||||||
|
func (s drawerSet) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("{ ")
|
||||||
|
for x := range s {
|
||||||
|
fmt.Fprintf(&sb, "%v ", x)
|
||||||
|
}
|
||||||
|
sb.WriteString("}")
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
type dag struct {
|
type dag struct {
|
||||||
|
all drawerSet
|
||||||
in, out map[Drawer]drawerSet
|
in, out map[Drawer]drawerSet
|
||||||
}
|
}
|
||||||
|
|
||||||
func newDAG() *dag {
|
func newDAG() *dag {
|
||||||
return &dag{
|
return &dag{
|
||||||
|
all: make(drawerSet),
|
||||||
in: make(map[Drawer]drawerSet),
|
in: make(map[Drawer]drawerSet),
|
||||||
out: make(map[Drawer]drawerSet),
|
out: make(map[Drawer]drawerSet),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *dag) String() string {
|
||||||
|
var sb strings.Builder
|
||||||
|
sb.WriteString("digraph {\n")
|
||||||
|
for v, e := range d.out {
|
||||||
|
fmt.Fprintf(&sb, "%v -> %v\n", v, e)
|
||||||
|
}
|
||||||
|
sb.WriteString(" }\n")
|
||||||
|
return sb.String()
|
||||||
|
}
|
||||||
|
|
||||||
// addEdge adds the edge u-v in O(1).
|
// addEdge adds the edge u-v in O(1).
|
||||||
func (d *dag) addEdge(u, v Drawer) {
|
func (d *dag) addEdge(u, v Drawer) {
|
||||||
|
d.all[u], d.all[v] = struct{}{}, struct{}{}
|
||||||
if d.in[v] == nil {
|
if d.in[v] == nil {
|
||||||
d.in[v] = make(drawerSet)
|
d.in[v] = make(drawerSet)
|
||||||
}
|
}
|
||||||
|
@ -231,11 +283,13 @@ func (d *dag) addEdge(u, v Drawer) {
|
||||||
d.out[u][v] = struct{}{}
|
d.out[u][v] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// removeEdge removes the edge u-v in O(1).
|
// removeEdge removes the edge u-v in O(1).
|
||||||
func (d *dag) removeEdge(u, v Drawer) {
|
func (d *dag) removeEdge(u, v Drawer) {
|
||||||
delete(d.in[v], u)
|
delete(d.in[v], u)
|
||||||
delete(d.out[u], v)
|
delete(d.out[u], v)
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// removeVertex removes all in and out edges associated with v in O(degree(v)).
|
// removeVertex removes all in and out edges associated with v in O(degree(v)).
|
||||||
func (d *dag) removeVertex(v Drawer) {
|
func (d *dag) removeVertex(v Drawer) {
|
||||||
|
@ -249,6 +303,7 @@ func (d *dag) removeVertex(v Drawer) {
|
||||||
}
|
}
|
||||||
delete(d.in, v)
|
delete(d.in, v)
|
||||||
delete(d.out, v)
|
delete(d.out, v)
|
||||||
|
delete(d.all, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// topIterate visits each vertex in topological order, in time O(|V| + |E|) and
|
// topIterate visits each vertex in topological order, in time O(|V| + |E|) and
|
||||||
|
@ -258,7 +313,9 @@ func (d *dag) topIterate(visit func(Drawer)) {
|
||||||
// If indegree(v) = 0, enqueue. Total: O(|V|).
|
// If indegree(v) = 0, enqueue. Total: O(|V|).
|
||||||
queue := make([]Drawer, 0, len(d.in))
|
queue := make([]Drawer, 0, len(d.in))
|
||||||
indegree := make(map[Drawer]int)
|
indegree := make(map[Drawer]int)
|
||||||
for u, e := range d.in {
|
for u := range d.all {
|
||||||
|
// NB: zero indegree vertices may be missing from d.in
|
||||||
|
e := d.in[u]
|
||||||
if len(e) == 0 {
|
if len(e) == 0 {
|
||||||
queue = append(queue, u)
|
queue = append(queue, u)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -25,7 +25,6 @@ type Fill struct {
|
||||||
ID
|
ID
|
||||||
Color color.Color
|
Color color.Color
|
||||||
Hides
|
Hides
|
||||||
ZPosition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Fill) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
func (f *Fill) Draw(screen *ebiten.Image, opts *ebiten.DrawImageOptions) {
|
||||||
|
|
|
@ -17,7 +17,10 @@ var (
|
||||||
BoundingBoxerType = reflect.TypeOf((*BoundingBoxer)(nil)).Elem()
|
BoundingBoxerType = reflect.TypeOf((*BoundingBoxer)(nil)).Elem()
|
||||||
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
|
ColliderType = reflect.TypeOf((*Collider)(nil)).Elem()
|
||||||
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
|
DisablerType = reflect.TypeOf((*Disabler)(nil)).Elem()
|
||||||
|
DrawLayerType = reflect.TypeOf((*DrawLayer)(nil)).Elem()
|
||||||
DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem()
|
DrawerType = reflect.TypeOf((*Drawer)(nil)).Elem()
|
||||||
|
DrawBoxerType = reflect.TypeOf((*DrawBoxer)(nil)).Elem()
|
||||||
|
DrawOrdererType = reflect.TypeOf((*DrawOrderer)(nil)).Elem()
|
||||||
HiderType = reflect.TypeOf((*Hider)(nil)).Elem()
|
HiderType = reflect.TypeOf((*Hider)(nil)).Elem()
|
||||||
IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem()
|
IdentifierType = reflect.TypeOf((*Identifier)(nil)).Elem()
|
||||||
LoaderType = reflect.TypeOf((*Loader)(nil)).Elem()
|
LoaderType = reflect.TypeOf((*Loader)(nil)).Elem()
|
||||||
|
@ -33,7 +36,10 @@ var (
|
||||||
BoundingBoxerType,
|
BoundingBoxerType,
|
||||||
ColliderType,
|
ColliderType,
|
||||||
DisablerType,
|
DisablerType,
|
||||||
|
DrawLayerType,
|
||||||
DrawerType,
|
DrawerType,
|
||||||
|
DrawBoxerType,
|
||||||
|
DrawOrdererType,
|
||||||
HiderType,
|
HiderType,
|
||||||
IdentifierType,
|
IdentifierType,
|
||||||
LoaderType,
|
LoaderType,
|
||||||
|
|
|
@ -39,9 +39,3 @@ func (h *Hides) Hide() { *h = true }
|
||||||
|
|
||||||
// Show sets h to false.
|
// Show sets h to false.
|
||||||
func (h *Hides) Show() { *h = false }
|
func (h *Hides) Show() { *h = false }
|
||||||
|
|
||||||
// ZPosition implements ZPositioner directly (as an int).
|
|
||||||
type ZPosition int
|
|
||||||
|
|
||||||
// ZPos returns itself.
|
|
||||||
func (z ZPosition) ZPos() int { return int(z) }
|
|
||||||
|
|
|
@ -44,7 +44,6 @@ type Tilemap struct {
|
||||||
Ersatz bool // disables collisions ("fake wall")
|
Ersatz bool // disables collisions ("fake wall")
|
||||||
Offset image.Point // world coordinates
|
Offset image.Point // world coordinates
|
||||||
Sheet Sheet
|
Sheet Sheet
|
||||||
ZPosition
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CollidesWith implements Collider.
|
// CollidesWith implements Collider.
|
||||||
|
|
|
@ -92,7 +92,6 @@ type WallUnit struct {
|
||||||
Disables
|
Disables
|
||||||
Hides
|
Hides
|
||||||
Tile Tile // chooses which cell in wall.Sheet to draw
|
Tile Tile // chooses which cell in wall.Sheet to draw
|
||||||
ZPosition
|
|
||||||
|
|
||||||
pos image.Point // tilespace coordinates
|
pos image.Point // tilespace coordinates
|
||||||
wall *Wall
|
wall *Wall
|
||||||
|
|
Loading…
Reference in a new issue