• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / arche-pixel / 7577733836

19 Jan 2024 12:30AM CUT coverage: 88.217%. Remained the same
7577733836

push

github

web-flow
Add the Arche logo to the README (#49)

1430 of 1621 relevant lines covered (88.22%)

223189.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.77
/window/window.go
1
package window
2

3
import (
4
        "fmt"
5
        "log"
6

7
        pixel "github.com/gopxl/pixel/v2"
8
        "github.com/gopxl/pixel/v2/backends/opengl"
9
        "github.com/mlange-42/arche-model/resource"
10
        "github.com/mlange-42/arche/ecs"
11
        "github.com/mlange-42/arche/generic"
12
        "golang.org/x/image/colornames"
13
)
14

15
// Drawer interface.
16
// Drawers are used by the [Window] to render information from an Arche model.
17
type Drawer interface {
18
        // Initialize is called before any other method.
19
        // Use it to initialize the Drawer.
20
        Initialize(w *ecs.World, win *opengl.Window)
21

22
        // Update is called with normal system updates.
23
        // Can be used to update observers.
24
        Update(w *ecs.World)
25

26
        // UpdateInputs is called on every UI update, i.e. with the frequency of FPS.
27
        // Can be used to handle user input of the previous frame update.
28
        UpdateInputs(w *ecs.World, win *opengl.Window)
29

30
        // Draw is called on UI updates, every [Model.DrawInterval] steps.
31
        // Draw is not called when the host window is minimized.
32
        // Do all OpenGL drawing on the window here.
33
        Draw(w *ecs.World, win *opengl.Window)
34
}
35

36
// Bounds define a bounding box for a window.
37
type Bounds struct {
38
        X int // X position
39
        Y int // Y position
40
        W int // Width
41
        H int // Height
42
}
43

44
// B created a new Bounds object.
45
func B(x, y, w, h int) Bounds {
1✔
46
        return Bounds{x, y, w, h}
1✔
47
}
1✔
48

49
// Window provides an OpenGL window for drawing.
50
// Drawing is done by one or more [Drawer] instances.
51
// Further, window bounds and update and draw intervals can be configured.
52
//
53
// If the world contains a resource of type [github.com/mlange-42/arche-model/resource/Termination],
54
// the model is terminated when the window is closed.
55
type Window struct {
56
        Title        string   // Window title. Optional.
57
        Bounds       Bounds   // Window bounds (position and size). Optional.
58
        Drawers      []Drawer // Drawers in increasing z order.
59
        DrawInterval int      // Interval for re-drawing, in UI frames. Optional.
60
        window       *opengl.Window
61
        drawStep     int64
62
        isClosed     bool
63
        termRes      generic.Resource[resource.Termination]
64
}
65

66
// With adds one or more [Drawer] instances to the window.
67
func (w *Window) With(drawers ...Drawer) *Window {
2✔
68
        w.Drawers = append(w.Drawers, drawers...)
2✔
69
        return w
2✔
70
}
2✔
71

72
// Initialize the window system.
73
func (w *Window) Initialize(world *ecs.World) {}
1✔
74

75
// InitializeUI the window system.
76
func (w *Window) InitializeUI(world *ecs.World) {
1✔
77
        if w.Bounds.W <= 0 {
2✔
78
                w.Bounds.W = 1024
1✔
79
        }
1✔
80
        if w.Bounds.H <= 0 {
2✔
81
                w.Bounds.H = 768
1✔
82
        }
1✔
83
        if w.Title == "" {
2✔
84
                w.Title = "Arche"
1✔
85
        }
1✔
86
        cfg := opengl.WindowConfig{
1✔
87
                Title:     w.Title,
1✔
88
                Bounds:    pixel.R(0, 0, float64(w.Bounds.W), float64(w.Bounds.H)),
1✔
89
                Position:  pixel.V(float64(w.Bounds.X), float64(w.Bounds.Y)),
1✔
90
                Resizable: true,
1✔
91
        }
1✔
92

1✔
93
        defer func() {
2✔
94
                if err := recover(); err != nil {
1✔
95
                        txt := fmt.Sprint(err)
×
96
                        if txt == "mainthread: did not call Run" {
×
97
                                log.Fatal("ERROR: when using graphics via the pixel engine, run the model like this:\n    window.Run(model)")
×
98
                        }
×
99
                        panic(err)
×
100
                }
101
        }()
102

103
        var err error
1✔
104
        w.window, err = opengl.NewWindow(cfg)
1✔
105
        if err != nil {
1✔
106
                panic(err)
×
107
        }
108
        for _, d := range w.Drawers {
2✔
109
                d.Initialize(world, w.window)
1✔
110
        }
1✔
111

112
        w.termRes = generic.NewResource[resource.Termination](world)
1✔
113
        w.drawStep = 0
1✔
114
        w.isClosed = false
1✔
115
}
116

117
// Update the window system.
118
func (w *Window) Update(world *ecs.World) {
100✔
119
        if w.isClosed {
100✔
120
                return
×
121
        }
×
122
        for _, d := range w.Drawers {
200✔
123
                d.Update(world)
100✔
124
        }
100✔
125
}
126

127
// UpdateUI the window system.
128
func (w *Window) UpdateUI(world *ecs.World) {
100✔
129
        if w.window.Closed() {
100✔
130
                if !w.isClosed {
×
131
                        term := w.termRes.Get()
×
132
                        if term != nil {
×
133
                                term.Terminate = true
×
134
                        }
×
135
                        w.isClosed = true
×
136
                }
137
                return
×
138
        }
139
        if !w.isMinimized() && (w.DrawInterval <= 1 || w.drawStep%int64(w.DrawInterval) == 0) {
200✔
140
                w.window.Clear(colornames.Black)
100✔
141

100✔
142
                for _, d := range w.Drawers {
200✔
143
                        d.Draw(world, w.window)
100✔
144
                }
100✔
145
        }
146
        w.drawStep++
100✔
147
}
148

149
func (w *Window) isMinimized() bool {
100✔
150
        b := w.window.Bounds()
100✔
151
        return b.W() <= 0 || b.H() <= 0
100✔
152
}
100✔
153

154
// PostUpdateUI updates the underlying GL window and input events.
155
func (w *Window) PostUpdateUI(world *ecs.World) {
100✔
156
        w.window.Update()
100✔
157
        for _, d := range w.Drawers {
200✔
158
                d.UpdateInputs(world, w.window)
100✔
159
        }
100✔
160
}
161

162
// Finalize the window system.
163
func (w *Window) Finalize(world *ecs.World) {}
1✔
164

165
// FinalizeUI the window system.
166
func (w *Window) FinalizeUI(world *ecs.World) {
1✔
167
        w.window.Destroy()
1✔
168
}
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc