-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathui.mar
375 lines (357 loc) · 17.1 KB
/
ui.mar
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
import stdlib.mar
fun get_screen_size(): Point asm {
syscall 13
load c sp store c a
moveib d 8 add c d
store c b
ret
}
| Color
| Represents a color, including opacity.
struct Color { r: Byte, g: Byte, b: Byte, a: Byte }
fun color(r: Byte, g: Byte, b: Byte, a: Byte): Color { Color { r, g, b, a } }
fun color(r: Byte, g: Byte, b: Byte): Color {
Color { r, g, b, a = 255.lower_byte() }
}
fun color(r: Int, g: Int, b: Int): Color {
color(r.lower_byte(), g.lower_byte(), b.lower_byte())
}
fun color(rgb: Int): Color {
color({rgb >> 16}.lower_byte(), {rgb >> 8}.lower_byte(), rgb.lower_byte())
}
var black = color( 0, 0, 0)
var white = color(255, 255, 255)
| Texture
struct Texture {
buffer: Slice[Color],
width: Int,
height: Int,
}
fun texture(size: Point): Texture {
Texture {
buffer = filled_slice(size.x * size.y, white),
width = size.x, height = size.y,
}
}
fun screen_texture(): Texture { texture(get_screen_size()) }
fun dimensions(texture: Texture): Point { texture.width @ texture.height }
fun get_ref(texture: &Texture, point: Point): &Color {
texture.buffer.&.get_maybe_ref(point.y * texture.width + point.x)
or panic("point {point} is not on {texture.width}x{texture.height} texture")
}
fun get(texture: Texture, point: Point): Color {
texture.&.get_ref(point).*
}
fun fill(texture: &Texture, color: Color) {
for x in 0..texture.width do
for y in 0..texture.height do
texture.get_ref(x @ y).* = color
}
fun draw(texture: &Texture, point: Point, color: Color) {
texture.get_ref(point).* = color
}
fun draw(texture: &Texture, rect: Rectangle, color: Color) {
for x in rect.left..rect.right do
for y in rect.top..rect.bottom do
texture.get_ref(x @ y).* = color
}
fun show(texture: Texture) asm {
moveib a 8 add a sp load a a | texture.buffer.data
moveib b 24 add b sp load b b | texture.width
moveib c 32 add c sp load c c | texture.height
| The texture contains colors in RGBA format, the ui_render syscall expects
| colors without alpha. So, here, we first transform the colors.
movei d heap_head load d d | raw texture stripped of alpha channel
move e b mul e c | e = number of pixels left to copy: width * height
| a = cursor through original pixels
move b d | b = cursor through new pixels
moveib f 1
.copy_color:
move st e isequal cjump .done
loadb c a store b c add a f add b f | copy r
loadb c a store b c add a f add b f | copy g
loadb c a store b c add a f add b f | copy b
add a f | skip alpha in the original
sub e f jump .copy_color
.done:
move a d
moveib b 24 add b sp load b b | texture.width
moveib c 32 add c sp load c c | texture.height
syscall 14 ret
}
| Font
| All letters are sized 5x8 pixels.
struct Glyph { a: Byte, b: Byte, c: Byte, d: Byte, e: Byte }
fun glyph(a: Int, b: Int, c: Int, d: Int, e: Int): Glyph {
Glyph {
a = a.lower_byte(),
b = b.lower_byte(),
c = c.lower_byte(),
d = d.lower_byte(),
e = e.lower_byte(),
}
}
var font = {
var map = map[Char, Glyph]().&
map.put(newline,
glyph(2#00100000, 2#01110000, 2#00100000, 2#00111000, 2#00000000))
map.put(# , glyph(2#00000000, 2#00000000, 2#00000000, 2#00000000, 2#00000000))
map.put(#!, glyph(2#00000000, 2#00000000, 2#01011111, 2#00000000, 2#00000000))
map.put(#", glyph(2#00000000, 2#00000111, 2#00000000, 2#00000111, 2#00000000))
map.put(##, glyph(2#00010100, 2#01111111, 2#00010100, 2#01111111, 2#00010100))
map.put(#$, glyph(2#00100100, 2#00101010, 2#01101011, 2#00101010, 2#00010010))
map.put(#%, glyph(2#01000011, 2#00110000, 2#00001000, 2#00000110, 2#01100001))
map.put(#&, glyph(2#00110000, 2#01001010, 2#01011101, 2#00110010, 2#01001000))
map.put(#', glyph(2#00000000, 2#00000000, 2#00000111, 2#00000000, 2#00000000))
map.put(#(, glyph(2#00000000, 2#00111110, 2#01000001, 2#01000001, 2#00000000))
map.put(#), glyph(2#00000000, 2#01000001, 2#01000001, 2#00111110, 2#00000000))
map.put(#*, glyph(2#00000000, 2#00010100, 2#00001000, 2#00010100, 2#00000000))
map.put(#+, glyph(2#00001000, 2#00001000, 2#00111110, 2#00001000, 2#00001000))
map.put(#,, glyph(2#00000000, 2#10000000, 2#01100000, 2#00000000, 2#00000000))
map.put(#-, glyph(2#00001000, 2#00001000, 2#00001000, 2#00001000, 2#00001000))
map.put(#., glyph(2#00000000, 2#00000000, 2#01100000, 2#00000000, 2#00000000))
map.put(#/, glyph(2#00100000, 2#00010000, 2#00001000, 2#00000100, 2#00000010))
map.put(#0, glyph(2#00111110, 2#01010001, 2#01001001, 2#01000101, 2#00111110))
map.put(#1, glyph(2#01000000, 2#01000010, 2#01111111, 2#01000000, 2#01000000))
map.put(#2, glyph(2#01100010, 2#01010001, 2#01001001, 2#01001001, 2#01000110))
map.put(#3, glyph(2#00100010, 2#01000001, 2#01001001, 2#01001001, 2#00110110))
map.put(#4, glyph(2#00011000, 2#00010100, 2#00010010, 2#00010001, 2#01111111))
map.put(#5, glyph(2#00100111, 2#01000101, 2#01000101, 2#01000101, 2#00111001))
map.put(#6, glyph(2#00111100, 2#01001010, 2#01001001, 2#01001001, 2#00110000))
map.put(#7, glyph(2#00000011, 2#00000001, 2#01110001, 2#00001001, 2#00000111))
map.put(#8, glyph(2#00110110, 2#01001001, 2#01001001, 2#01001001, 2#00110110))
map.put(#9, glyph(2#00000110, 2#01001001, 2#01001001, 2#00101001, 2#00011110))
map.put(#:, glyph(2#00000000, 2#00000000, 2#01100110, 2#00000000, 2#00000000))
map.put(#;, glyph(2#00000000, 2#10000000, 2#01100110, 2#00000000, 2#00000000))
map.put(#<, glyph(2#00001000, 2#00010100, 2#00100010, 2#01000001, 2#00000000))
map.put(#=, glyph(2#00100100, 2#00100100, 2#00100100, 2#00100100, 2#00100100))
map.put(#>, glyph(2#00000000, 2#01000001, 2#00100010, 2#00010100, 2#00001000))
map.put(#?, glyph(2#00000010, 2#00000001, 2#01010001, 2#00001001, 2#00000110))
map.put(#@, glyph(2#00111110, 2#01000001, 2#01011101, 2#01010001, 2#00011110))
map.put(#A, glyph(2#01111110, 2#00000101, 2#00000101, 2#00000101, 2#01111110))
map.put(#B, glyph(2#01111111, 2#01000101, 2#01000101, 2#01000101, 2#00111010))
map.put(#C, glyph(2#00111110, 2#01000001, 2#01000001, 2#01000001, 2#00100010))
map.put(#D, glyph(2#01111111, 2#01000001, 2#01000001, 2#01000001, 2#00111110))
map.put(#E, glyph(2#01111111, 2#01000101, 2#01000101, 2#01000001, 2#01000001))
map.put(#F, glyph(2#01111111, 2#00000101, 2#00000101, 2#00000001, 2#00000001))
map.put(#G, glyph(2#00111110, 2#01000001, 2#01000001, 2#01000101, 2#00111101))
map.put(#H, glyph(2#01111111, 2#00000100, 2#00000100, 2#00000100, 2#01111111))
map.put(#I, glyph(2#00000000, 2#01000001, 2#01111111, 2#01000001, 2#00000000))
map.put(#J, glyph(2#00100000, 2#01000000, 2#01000000, 2#01000000, 2#00111111))
map.put(#K, glyph(2#01111111, 2#00000100, 2#00000100, 2#00001010, 2#01110001))
map.put(#L, glyph(2#01111111, 2#01000000, 2#01000000, 2#01000000, 2#01000000))
map.put(#M, glyph(2#01111111, 2#00000010, 2#00000100, 2#00000010, 2#01111111))
map.put(#N, glyph(2#01111111, 2#00000010, 2#00000100, 2#00001000, 2#01111111))
map.put(#O, glyph(2#00111110, 2#01000001, 2#01000001, 2#01000001, 2#00111110))
map.put(#P, glyph(2#01111111, 2#00000101, 2#00000101, 2#00000101, 2#00000010))
map.put(#Q, glyph(2#00111110, 2#01000001, 2#01000001, 2#00100001, 2#01011110))
map.put(#R, glyph(2#01111111, 2#00000101, 2#00000101, 2#00000101, 2#01111010))
map.put(#S, glyph(2#00100010, 2#01000101, 2#01000101, 2#01000101, 2#00111001))
map.put(#T, glyph(2#00000001, 2#00000001, 2#01111111, 2#00000001, 2#00000001))
map.put(#U, glyph(2#00111111, 2#01000000, 2#01000000, 2#01000000, 2#00111111))
map.put(#V, glyph(2#00001111, 2#00110000, 2#01000000, 2#00110000, 2#00001111))
map.put(#W, glyph(2#01111111, 2#00100000, 2#00010000, 2#00100000, 2#01111111))
map.put(#X, glyph(2#01110001, 2#00001010, 2#00000100, 2#00001010, 2#01110001))
map.put(#Y, glyph(2#00000001, 2#00000010, 2#01111100, 2#00000010, 2#00000001))
map.put(#Z, glyph(2#01100001, 2#01010001, 2#01001001, 2#01000101, 2#01000011))
map.put(#[, glyph(2#00000000, 2#01111111, 2#01000001, 2#01000001, 2#00000000))
map.put(#\, glyph(2#00000001, 2#00000110, 2#00001000, 2#00110000, 2#01000000))
map.put(#], glyph(2#00000000, 2#01000001, 2#01000001, 2#01111111, 2#00000000))
map.put(#^, glyph(2#00000100, 2#00000010, 2#00000001, 2#00000010, 2#00000100))
map.put(#_, glyph(2#10000000, 2#10000000, 2#10000000, 2#10000000, 2#10000000))
map.put(#`, glyph(2#00000000, 2#00000000, 2#00000001, 2#00000010, 2#00000000))
map.put(#a, glyph(2#00100000, 2#01010100, 2#01010100, 2#01010100, 2#01111000))
map.put(#b, glyph(2#01111111, 2#01001000, 2#01000100, 2#01000100, 2#00111000))
map.put(#c, glyph(2#00111000, 2#01000100, 2#01000100, 2#01000100, 2#00101000))
map.put(#d, glyph(2#00111000, 2#01000100, 2#01000100, 2#01001000, 2#01111111))
map.put(#e, glyph(2#00111000, 2#01010100, 2#01010100, 2#01010100, 2#01011000))
map.put(#f, glyph(2#00000100, 2#00000100, 2#01111110, 2#00000101, 2#00000101))
map.put(#g, glyph(2#10011000, 2#10100100, 2#10100100, 2#10100100, 2#01111100))
map.put(#h, glyph(2#01111111, 2#00001000, 2#00000100, 2#00000100, 2#01111000))
map.put(#i, glyph(2#01000100, 2#01000100, 2#01111101, 2#01000000, 2#01000000))
map.put(#j, glyph(2#01000000, 2#10000000, 2#10000100, 2#10000100, 2#01111101))
map.put(#k, glyph(2#01111111, 2#00010000, 2#00010000, 2#00101000, 2#01000100))
map.put(#l, glyph(2#01000001, 2#01000001, 2#01111111, 2#01000000, 2#01000000))
map.put(#m, glyph(2#01111100, 2#00000100, 2#00011000, 2#00000100, 2#01111000))
map.put(#n, glyph(2#01111100, 2#00000100, 2#00000100, 2#00000100, 2#01111000))
map.put(#o, glyph(2#00111000, 2#01000100, 2#01000100, 2#01000100, 2#00111000))
map.put(#p, glyph(2#11111100, 2#00101000, 2#00100100, 2#00100100, 2#00011000))
map.put(#q, glyph(2#00011000, 2#00100100, 2#00100100, 2#00101000, 2#11111100))
map.put(#r, glyph(2#01111100, 2#00001000, 2#00000100, 2#00000100, 2#00001000))
map.put(#s, glyph(2#01001000, 2#01010100, 2#01010100, 2#01010100, 2#00100100))
map.put(#t, glyph(2#00000100, 2#00000100, 2#00111111, 2#01000100, 2#01000100))
map.put(#u, glyph(2#00111100, 2#01000000, 2#01000000, 2#01000000, 2#01111100))
map.put(#v, glyph(2#00001100, 2#00110000, 2#01000000, 2#00110000, 2#00001100))
map.put(#w, glyph(2#00111100, 2#01000000, 2#01110000, 2#01000000, 2#01111100))
map.put(#x, glyph(2#01000100, 2#00101000, 2#00010000, 2#00101000, 2#01000100))
map.put(#y, glyph(2#10011100, 2#10100000, 2#10100000, 2#10100000, 2#01111100))
map.put(#z, glyph(2#01000100, 2#01100100, 2#01010100, 2#01001100, 2#01000100))
map.put(#{, glyph(2#00001000, 2#00001000, 2#00110110, 2#01000001, 2#00000000))
map.put(#|, glyph(2#00000000, 2#00000000, 2#01111111, 2#00000000, 2#00000000))
map.put(#}, glyph(2#00000000, 2#01000001, 2#00110110, 2#00001000, 2#00001000))
map.put(#~, glyph(2#00001000, 2#00000100, 2#00000100, 2#00001000, 2#00000100))
map.*
}
fun draw(texture: &Texture, char: Char, where: Point, size: Int, color: Color) {
switch font.get_maybe(char)
case none texture.draw({where.x @ where.y}.by({5 @ 8} * size), color)
case some(glyph)
for x in 0..5 do for y in 0..8 do {
var glyph_col =
if x == 0 then glyph.a else if x == 1 then glyph.b
else if x == 2 then glyph.c else if x == 3 then glyph.d else glyph.e
var bit = glyph_col.to_int()
for i in 0..y do bit = bit / 2
var is_set = bit % 2 == 1
if is_set then
texture.draw({where + {{x @ y} * size}}.by(size @ size), color)
}
}
fun draw(
texture: &Texture, string: String, where: Point, size: Int, color: Color
) {
for it in string.iter().enumerate() do
texture.draw(it.item, where + {6 * it.index * size @ 0}, size, color)
}
| Input
enum KeyboardKey {
apostrophe, comma, minus, period, slash,
zero, one, two, three, four, five, six, seven, eight, nine,
semicolon, equal,
a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z,
space, escape, enter, tab, backspace, insert, delete,
right, left, down, up,
page_up, page_down, home, end,
caps_lock, scroll_lock, num_lock,
print_screen, pause,
f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12,
left_shift, left_control, left_alt, left_super,
right_shift, right_control, right_alt, right_super,
kb_menu, left_bracket,
backslash, right_bracket,
grave,
kp_0, kp_1, kp_2, kp_3, kp_4, kp_5, kp_6, kp_7, kp_8, kp_9,
kp_decimal, kp_divide, kp_multiply, kp_subtract, kp_add, kp_enter, kp_equal,
back,
volume_up, volume_down,
}
fun get_pressed_key(): Maybe[KeyboardKey] {
var id = raw_get_key_pressed()
if id == 0 then none[KeyboardKey]()
else some[KeyboardKey](
if id == 4 then KeyboardKey.back
else if id == 24 then KeyboardKey.volume_up
else if id == 25 then KeyboardKey.volume_down
else if id == 32 then KeyboardKey.space
else if id == 39 then KeyboardKey.apostrophe
else if id == 44 then KeyboardKey.comma
else if id == 45 then KeyboardKey.minus
else if id == 46 then KeyboardKey.period
else if id == 47 then KeyboardKey.slash
else if id == 48 then KeyboardKey.zero
else if id == 49 then KeyboardKey.one
else if id == 50 then KeyboardKey.two
else if id == 51 then KeyboardKey.three
else if id == 52 then KeyboardKey.four
else if id == 53 then KeyboardKey.five
else if id == 54 then KeyboardKey.six
else if id == 55 then KeyboardKey.seven
else if id == 56 then KeyboardKey.eight
else if id == 57 then KeyboardKey.nine
else if id == 59 then KeyboardKey.semicolon
else if id == 61 then KeyboardKey.equal
else if id == 65 then KeyboardKey.a
else if id == 66 then KeyboardKey.b
else if id == 67 then KeyboardKey.c
else if id == 68 then KeyboardKey.d
else if id == 69 then KeyboardKey.e
else if id == 70 then KeyboardKey.f
else if id == 71 then KeyboardKey.g
else if id == 72 then KeyboardKey.h
else if id == 73 then KeyboardKey.i
else if id == 74 then KeyboardKey.j
else if id == 75 then KeyboardKey.k
else if id == 76 then KeyboardKey.l
else if id == 77 then KeyboardKey.m
else if id == 78 then KeyboardKey.n
else if id == 79 then KeyboardKey.o
else if id == 80 then KeyboardKey.p
else if id == 81 then KeyboardKey.q
else if id == 82 then KeyboardKey.r
else if id == 83 then KeyboardKey.s
else if id == 84 then KeyboardKey.t
else if id == 85 then KeyboardKey.u
else if id == 86 then KeyboardKey.v
else if id == 87 then KeyboardKey.w
else if id == 88 then KeyboardKey.x
else if id == 89 then KeyboardKey.y
else if id == 90 then KeyboardKey.z
else if id == 91 then KeyboardKey.left_bracket
else if id == 92 then KeyboardKey.backslash
else if id == 93 then KeyboardKey.right_bracket
else if id == 96 then KeyboardKey.grave
else if id == 256 then KeyboardKey.escape
else if id == 257 then KeyboardKey.enter
else if id == 258 then KeyboardKey.tab
else if id == 259 then KeyboardKey.backspace
else if id == 260 then KeyboardKey.insert
else if id == 261 then KeyboardKey.delete
else if id == 262 then KeyboardKey.right
else if id == 263 then KeyboardKey.left
else if id == 264 then KeyboardKey.down
else if id == 265 then KeyboardKey.up
else if id == 266 then KeyboardKey.page_up
else if id == 267 then KeyboardKey.page_down
else if id == 268 then KeyboardKey.home
else if id == 269 then KeyboardKey.end
else if id == 280 then KeyboardKey.caps_lock
else if id == 281 then KeyboardKey.scroll_lock
else if id == 282 then KeyboardKey.num_lock
else if id == 283 then KeyboardKey.print_screen
else if id == 284 then KeyboardKey.pause
else if id == 290 then KeyboardKey.f1
else if id == 291 then KeyboardKey.f2
else if id == 292 then KeyboardKey.f3
else if id == 293 then KeyboardKey.f4
else if id == 294 then KeyboardKey.f5
else if id == 295 then KeyboardKey.f6
else if id == 296 then KeyboardKey.f7
else if id == 297 then KeyboardKey.f8
else if id == 298 then KeyboardKey.f9
else if id == 299 then KeyboardKey.f10
else if id == 300 then KeyboardKey.f11
else if id == 301 then KeyboardKey.f12
else if id == 320 then KeyboardKey.kp_0
else if id == 321 then KeyboardKey.kp_1
else if id == 322 then KeyboardKey.kp_2
else if id == 323 then KeyboardKey.kp_3
else if id == 324 then KeyboardKey.kp_4
else if id == 325 then KeyboardKey.kp_5
else if id == 326 then KeyboardKey.kp_6
else if id == 327 then KeyboardKey.kp_7
else if id == 328 then KeyboardKey.kp_8
else if id == 329 then KeyboardKey.kp_9
else if id == 330 then KeyboardKey.kp_decimal
else if id == 331 then KeyboardKey.kp_divide
else if id == 332 then KeyboardKey.kp_multiply
else if id == 333 then KeyboardKey.kp_subtract
else if id == 334 then KeyboardKey.kp_add
else if id == 335 then KeyboardKey.kp_enter
else if id == 336 then KeyboardKey.kp_equal
else if id == 340 then KeyboardKey.left_shift
else if id == 341 then KeyboardKey.left_control
else if id == 342 then KeyboardKey.left_alt
else if id == 343 then KeyboardKey.left_super
else if id == 344 then KeyboardKey.right_shift
else if id == 345 then KeyboardKey.right_control
else if id == 346 then KeyboardKey.right_alt
else if id == 347 then KeyboardKey.right_super
else if id == 348 then KeyboardKey.kb_menu
else panic("unknown key id {id}")
)
}
fun raw_get_key_pressed(): Int asm {
syscall 15
load b sp store b a
ret
}