forked from oakmound/oak
/
drawStack.go
142 lines (124 loc) · 3.62 KB
/
drawStack.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package render
import (
"errors"
"image"
"image/draw"
"github.com/oakmound/oak/dlog"
)
var (
// GlobalDrawStack is the stack that all draw calls are parsed through.
GlobalDrawStack = &DrawStack{
as: []Addable{NewHeap(false)},
}
initialDrawStack = GlobalDrawStack
)
//The DrawStack is a stack with a safe adding mechanism that creates isolation between draw steps via predraw
type DrawStack struct {
as []Addable
toPush []Addable
toPop int
}
// An Addable manages Renderables
type Addable interface {
PreDraw()
Add(Renderable, int) Renderable
Replace(Renderable, Renderable, int)
Copy() Addable
draw(draw.Image, image.Point, int, int)
}
//SetDrawStack takes in a set of Addables which act as the set of Drawstacks available
func SetDrawStack(as ...Addable) {
GlobalDrawStack = &DrawStack{as: as}
initialDrawStack = GlobalDrawStack.Copy()
dlog.Info("Global", GlobalDrawStack)
dlog.Info("Initial", initialDrawStack)
}
//ResetDrawStack resets the Global stack back to the initial stack
func ResetDrawStack() {
GlobalDrawStack = initialDrawStack.Copy()
}
//Draw actively draws the onto the actual screen
func (ds *DrawStack) Draw(world draw.Image, view image.Point, w, h int) {
for _, a := range ds.as {
// If we had concurrent operations, we'd do it here
// in that case each draw call would return to us something
// to composite onto the window / world
a.draw(world, view, w, h)
}
}
//Draw accesses the global draw stack
func Draw(r Renderable, l int) (Renderable, error) {
if r == nil {
dlog.Error("Tried to draw nil")
return nil, errors.New("Tried to draw nil")
}
// If there's only one element, l refers to the layer
// within that element.
if len(GlobalDrawStack.as) == 1 {
return GlobalDrawStack.as[0].Add(r, l), nil
// Otherwise, l refers to the index within the DrawStack.
}
if l < 0 || l >= len(GlobalDrawStack.as) {
dlog.Error("Layer", l, "does not exist on global draw stack")
return nil, errors.New("Layer does not exist on stack")
}
return GlobalDrawStack.as[l].Add(r, r.GetLayer()), nil
}
// ReplaceDraw will undraw r1 and draw r2 after the next draw frame
// Useful for not working
func ReplaceDraw(r1, r2 Renderable, stackLayer, layer int) {
if r1 == nil || r2 == nil {
dlog.Error("Tried to draw nil")
return
}
if stackLayer < 0 || stackLayer >= len(GlobalDrawStack.as) {
dlog.Error("Layer", stackLayer, "does not exist on global draw stack")
return
}
r2.SetLayer(layer)
GlobalDrawStack.as[stackLayer].Replace(r1, r2, layer)
}
//Push appends an addable to the draw stack during the next predraw
func (ds *DrawStack) Push(a Addable) {
ds.toPush = append(ds.toPush, a)
}
//Pop increments the pop counter
func (ds *DrawStack) Pop() {
ds.toPop++
}
//PreDraw takes care of popping and pushing onto the stack. This helps safegaurd against operations taking place in the middle of a draw
func (ds *DrawStack) PreDraw() {
if ds.toPop > 0 {
ds.as = ds.as[0 : len(ds.as)-ds.toPop]
ds.toPop = 0
}
if len(ds.toPush) > 0 {
ds.as = append(ds.as, ds.toPush...)
// Should use two toPush lists, for this and
// draw heaps, so this call won't ever drop anything
ds.toPush = []Addable{}
}
for _, a := range ds.as {
a.PreDraw()
}
}
//Copy creates a new deep copy of a Drawstack
func (ds *DrawStack) Copy() *DrawStack {
ds2 := new(DrawStack)
ds2.as = make([]Addable, len(ds.as))
for i, a := range ds.as {
ds2.as[i] = a.Copy()
}
ds2.toPop = ds.toPop
ds2.toPush = ds.toPush
return ds2
}
//PreDraw tries to reset the GlobalDrawStack or performs the GlobalDrawStack's predraw functions
func PreDraw() {
if resetDraw {
ResetDrawStack()
resetDraw = false
} else {
GlobalDrawStack.PreDraw()
}
}