about summary refs log tree commit diff stats
path: root/apps/ex11.mu
blob: 6b967724c6c458edc2f763a5006811f55e247f42 (plain) (blame)
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
# Demo of an interactive app: controlling a Bezier curve on screen
#
# To build a disk image:
#   ./translate apps/ex11.mu       # emits code.img
# To run:
#   qemu-system-i386 code.img
# Or:
#   bochs -f bochsrc               # bochsrc loads code.img
#
# Expected output: a spline with 3 control points. Use `Tab` to switch cursor
# between control points, and arrow keys to move the control point at the
# cursor.

fn main screen: (addr screen), keyboard: (addr keyboard), data-disk: (addr disk) {
  var env-storage: environment
  var env/esi: (addr environment) <- address env-storage
  initialize-environment env, 0x200 0x20, 0x180 0x90, 0x180 0x160
  {
    render screen, env
    edit keyboard, env
    loop
  }
}

type environment {
  p0: (handle point)
  p1: (handle point)
  p2: (handle point)
  cursor: (handle point)  # one of p0, p1 or p2
}

type point {
  x: int
  y: int
}

fn render screen: (addr screen), _self: (addr environment) {
  clear-screen screen
  var self/esi: (addr environment) <- copy _self
  var tmp-ah/ecx: (addr handle point) <- get self, p0
  var tmp/eax: (addr point) <- lookup *tmp-ah
  var p0/ebx: (addr point) <- copy tmp
  tmp-ah <- get self, p1
  tmp <- lookup *tmp-ah
  var p1/edx: (addr point) <- copy tmp
  tmp-ah <- get self, p2
  tmp <- lookup *tmp-ah
  var p2/ecx: (addr point) <- copy tmp
  # control lines
  line    screen, p0, p1,                 7/color
  line    screen, p1, p2,                 7/color
  # curve above control lines
  bezier  screen, p0, p1, p2,             0xc/color
  # points above curve
  disc    screen, p0,           3/radius, 7/color   0xf/border
  disc    screen, p1,           3/radius, 7/color   0xf/border
  disc    screen, p2,           3/radius, 7/color   0xf/border
  # cursor last of all
  var cursor-ah/eax: (addr handle point) <- get self, cursor
  var cursor/eax: (addr point) <- lookup *cursor-ah
  cursor screen, cursor, 0xa/side, 3/color
}

fn bezier screen: (addr screen), _p0: (addr point), _p1: (addr point), _p2: (addr point), color: int {
  var p0/esi: (addr point) <- copy _p0
  var x0/ecx: (addr int) <- get p0, x
  var y0/edx: (addr int) <- get p0, y
  var p1/esi: (addr point) <- copy _p1
  var x1/ebx: (addr int) <- get p1, x
  var y1/eax: (addr int) <- get p1, y
  var p2/esi: (addr point) <- copy _p2
  var x2/edi: (addr int) <- get p2, x
  var y2/esi: (addr int) <- get p2, y
  draw-monotonic-bezier screen, *x0 *y0, *x1 *y1, *x2 *y2, color
}

fn cursor screen: (addr screen), _p: (addr point), side: int, color: int {
  var half-side/eax: int <- copy side
  half-side <- shift-right 1
  var p/esi: (addr point) <- copy _p
  var x-a/ecx: (addr int) <- get p, x
  var left-x/ecx: int <- copy *x-a
  left-x <- subtract half-side
  var y-a/edx: (addr int) <- get p, y
  var top-y/edx: int <- copy *y-a
  top-y <- subtract half-side
  var max/eax: int <- copy left-x
  max <- add side
  draw-horizontal-line screen, top-y, left-x, max, color
  max <- copy top-y
  max <- add side
  draw-vertical-line screen, left-x, top-y, max, color
  var right-x/ebx: int <- copy left-x
  right-x <- add side
  draw-vertical-line screen, right-x, top-y, max, color
  var bottom-y/edx: int <- copy top-y
  bottom-y <- add side
  draw-horizontal-line screen, bottom-y, left-x, right-x, color
}

fn edit keyboard: (addr keyboard), _self: (addr environment) {
  var self/esi: (addr environment) <- copy _self
  var key/eax: byte <- read-key keyboard
  compare key, 0
  loop-if-=
  {
    compare key, 9/tab
    break-if-!=
    toggle-cursor self
    return
  }
  {
    compare key, 0x80/left-arrow
    break-if-!=
    cursor-left self
    return
  }
  {
    compare key, 0x83/right-arrow
    break-if-!=
    cursor-right self
    return
  }
  {
    compare key, 0x81/down-arrow
    break-if-!=
    cursor-down self
    return
  }
  {
    compare key, 0x82/up-arrow
    break-if-!=
    cursor-up self
    return
  }
}

fn toggle-cursor _self: (addr environment) {
  var self/esi: (addr environment) <- copy _self
  var cursor-ah/edi: (addr handle point) <- get self, cursor
  var p0-ah/ecx: (addr handle point) <- get self, p0
  var p1-ah/edx: (addr handle point) <- get self, p1
  var p2-ah/ebx: (addr handle point) <- get self, p2
  {
    var p0?/eax: boolean <- handle-equal? *p0-ah, *cursor-ah
    compare p0?, 0/false
    break-if-=
    copy-object p1-ah, cursor-ah
    return
  }
  {
    var p1?/eax: boolean <- handle-equal? *p1-ah, *cursor-ah
    compare p1?, 0/false
    break-if-=
    copy-object p2-ah, cursor-ah
    return
  }
  {
    var p2?/eax: boolean <- handle-equal? *p2-ah, *cursor-ah
    compare p2?, 0/false
    break-if-=
    copy-object p0-ah, cursor-ah
    return
  }
  abort "lost cursor"
}

fn cursor-left _self: (addr environment) {
  var self/esi: (addr environment) <- copy _self
  var cursor-ah/esi: (addr handle point) <- get self, cursor
  var cursor/eax: (addr point) <- lookup *cursor-ah
  var cursor-x/eax: (addr int) <- get cursor, x
  compare *cursor-x, 0x20
  {
    break-if-<
    subtract-from *cursor-x, 0x20
  }
}

fn cursor-right _self: (addr environment) {
  var self/esi: (addr environment) <- copy _self
  var cursor-ah/esi: (addr handle point) <- get self, cursor
  var cursor/eax: (addr point) <- lookup *cursor-ah
  var cursor-x/eax: (addr int) <- get cursor, x
  compare *cursor-x, 0x3f0
  {
    break-if->
    add-to *cursor-x, 0x20
  }
}

fn cursor-up _self: (addr environment) {
  var self/esi: (addr environment) <- copy _self
  var cursor-ah/esi: (addr handle point) <- get self, cursor
  var cursor/eax: (addr point) <- lookup *cursor-ah
  var cursor-y/eax: (addr int) <- get cursor, y
  compare *cursor-y, 0x20
  {
    break-if-<
    subtract-from *cursor-y, 0x20
  }
}

fn cursor-down _self: (addr environment) {
  var self/esi: (addr environment) <- copy _self
  var cursor-ah/esi: (addr handle point) <- get self, cursor
  var cursor/eax: (addr point) <- lookup *cursor-ah
  var cursor-y/eax: (addr int) <- get cursor, y
  compare *cursor-y, 0x2f0
  {
    break-if->
    add-to *cursor-y, 0x20
  }
}

fn line screen: (addr screen), _p0: (addr point), _p1: (addr point), color: int {
  var p0/esi: (addr point) <- copy _p0
  var x0/ecx: (addr int) <- get p0, x
  var y0/edx: (addr int) <- get p0, y
  var p1/esi: (addr point) <- copy _p1
  var x1/ebx: (addr int) <- get p1, x
  var y1/eax: (addr int) <- get p1, y
  draw-line screen, *x0 *y0, *x1 *y1, color
}

fn disc screen: (addr screen), _p: (addr point), radius: int, color: int, border-color: int {
  var p/esi: (addr point) <- copy _p
  var x/ecx: (addr int) <- get p, x
  var y/edx: (addr int) <- get p, y
  draw-disc screen, *x *y, radius, color, border-color
}

fn initialize-environment _self: (addr environment), x0: int, y0: int, x1: int, y1: int, x2: int, y2: int {
  var self/esi: (addr environment) <- copy _self
  var p0-ah/eax: (addr handle point) <- get self, p0
  allocate p0-ah
  var p0/eax: (addr point) <- lookup *p0-ah
  initialize-point p0, x0 y0
  var p1-ah/eax: (addr handle point) <- get self, p1
  allocate p1-ah
  var p1/eax: (addr point) <- lookup *p1-ah
  initialize-point p1, x1 y1
  var p2-ah/eax: (addr handle point) <- get self, p2
  allocate p2-ah
  var p2/eax: (addr point) <- lookup *p2-ah
  initialize-point p2, x2 y2
  # cursor initially at p0
  var cursor-ah/edi: (addr handle point) <- get self, cursor
  var src-ah/esi: (addr handle point) <- get self, p0
  copy-object src-ah, cursor-ah
}

fn initialize-point _p: (addr point), x: int, y: int {
  var p/esi: (addr point) <- copy _p
  var dest/eax: (addr int) <- get p, x
  var src/ecx: int <- copy x
  copy-to *dest, src
  dest <- get p, y
  src <- copy y
  copy-to *dest, src
}