@@ -11,14 +11,22 @@ import (
11
11
"github.com/hajimehoshi/ebiten/v2"
12
12
13
13
"github.com/elgopher/pi"
14
+ "github.com/elgopher/pi/image"
14
15
"github.com/elgopher/pi/key"
15
16
)
16
17
17
18
type game struct {
18
19
ready atomic.Bool
19
- screenDataRGBA []byte // reused RGBA pixels
20
- screenChanged bool
21
20
shouldSkipNextDraw bool
21
+ screenFrame screenFrame
22
+ }
23
+
24
+ type screenFrame struct {
25
+ changed bool
26
+ pix []byte
27
+ palette [256 ]image.RGB
28
+ pald pi.PalMapping
29
+ screenDataRGBA []byte // reused RGBA pixels
22
30
}
23
31
24
32
func (e * game ) Update () error {
@@ -58,11 +66,39 @@ func (e *game) Update() error {
58
66
}
59
67
}
60
68
61
- e .screenChanged = true
69
+ e .screenFrame . update ()
62
70
63
71
return nil
64
72
}
65
73
74
+ func (f * screenFrame ) update () {
75
+ scrPix := pi .Scr ().Pix ()
76
+ screenChanged := ! slicesEqual (f .pix , scrPix ) || f .palette != pi .Palette || f .pald != pi .Pald
77
+ if screenChanged {
78
+ f .changed = true
79
+
80
+ if len (f .pix ) != len (scrPix ) {
81
+ f .pix = make ([]byte , len (scrPix ))
82
+ }
83
+ copy (f .pix , scrPix )
84
+ f .pald = pi .Pald
85
+ f .palette = pi .Palette
86
+ }
87
+ }
88
+
89
+ // replace with slices.Equal after upgrading to go 1.21
90
+ func slicesEqual [S ~ []E , E comparable ](s1 , s2 S ) bool {
91
+ if len (s1 ) != len (s2 ) {
92
+ return false
93
+ }
94
+ for i := range s1 {
95
+ if s1 [i ] != s2 [i ] {
96
+ return false
97
+ }
98
+ }
99
+ return true
100
+ }
101
+
66
102
func handleKeyboardShortcuts () {
67
103
f11 := key .Duration [key .F11 ] == 1
68
104
altEnter := key .Duration [key .Enter ] == 1 && key .Duration [key .Alt ] > 0
@@ -77,33 +113,30 @@ func (e *game) Draw(screen *ebiten.Image) {
77
113
return
78
114
}
79
115
80
- // Ebitengine executes Draw based on display frequency.
81
- // But the screen is changed at most 30 times per second.
82
- // That's why there is no need to write pixels more often
83
- // than 30 times per second.
84
- if e .screenChanged {
85
- e .writeScreenPixels (screen )
86
- e .screenChanged = false
87
- }
116
+ e .screenFrame .writeScreenPixels (screen )
88
117
}
89
118
90
- func (e * game ) writeScreenPixels (screen * ebiten.Image ) {
91
- pix := pi .Scr ().Pix ()
92
- if e .screenDataRGBA == nil || len (e .screenDataRGBA )/ 4 != len (pix ) {
93
- e .screenDataRGBA = make ([]byte , len (pix )* 4 )
94
- }
119
+ func (f * screenFrame ) writeScreenPixels (screen * ebiten.Image ) {
120
+ if f .changed {
121
+ f .changed = false
95
122
96
- offset := 0
97
- for _ , col := range pix {
98
- rgb := pi.Palette [pi.Pald [col ]]
99
- e .screenDataRGBA [offset ] = rgb .R
100
- e .screenDataRGBA [offset + 1 ] = rgb .G
101
- e .screenDataRGBA [offset + 2 ] = rgb .B
102
- e .screenDataRGBA [offset + 3 ] = 0xff
103
- offset += 4
104
- }
123
+ pix := pi .Scr ().Pix ()
124
+ if f .screenDataRGBA == nil || len (f .screenDataRGBA )/ 4 != len (pix ) {
125
+ f .screenDataRGBA = make ([]byte , len (pix )* 4 )
126
+ }
127
+
128
+ offset := 0
129
+ for _ , col := range pix {
130
+ rgb := pi.Palette [pi.Pald [col ]]
131
+ f .screenDataRGBA [offset ] = rgb .R
132
+ f .screenDataRGBA [offset + 1 ] = rgb .G
133
+ f .screenDataRGBA [offset + 2 ] = rgb .B
134
+ f .screenDataRGBA [offset + 3 ] = 0xff
135
+ offset += 4
136
+ }
105
137
106
- screen .WritePixels (e .screenDataRGBA )
138
+ screen .WritePixels (f .screenDataRGBA )
139
+ }
107
140
}
108
141
109
142
func (e * game ) Layout (outsideWidth , outsideHeight int ) (screenWidth , screenHeight int ) {
0 commit comments