-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrender_core.8o
265 lines (197 loc) · 7.16 KB
/
render_core.8o
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
:if KEEP_META_COMMENTS
# Include this file:
# 1. After font metadata definitions
# 2. Before the main body of your program
# Forgiving ifndef-like imports for dependencies.
:end
:unless TERMLIB_COMMON :include "common.8o" :end
:unless TERMLIB_DRAWING :include "drawing.8o" :end
###################################################################
### Text rendering core ###
###################################################################
# This section contains the high-level description of how to render
# text. The character-specific functions are kept in render_impl.8o,
# and can be overridden by defining the following before including
# render_impl.8o:
# 1. A CUSTOM_$FUNC_NAME constant as shown in the file
# 2. The corresponding function
# UI data we'll need
:const GLYPH_WIDTH_PX 4 # Usable glyph area
:const GLYPH_HEIGHT_PX 7 # Usable glyph area
:const GLYPH_TRACKING_PX 1 # Space between the characters
:const LINE_LEADING_PX 1 # Space after lines
:calc GLYPH_STEP_X_PX { GLYPH_WIDTH_PX + GLYPH_TRACKING_PX }
:calc GLYPH_STEP_Y_PX { GLYPH_HEIGHT_PX + LINE_LEADING_PX }
:const GLYPH_DATA_HEIGHT_PX 6 # Standard glyphs have this height
:calc GLYPH_DATA_LENGTH_BYTES { 2 * GLYPH_DATA_HEIGHT_PX }
:calc HIGHLIGHT_HEIGHT_PX { GLYPH_DATA_HEIGHT_PX + 1 }
# Where on screen the current message starts
:alias msg_start_x v9
:alias msg_start_y vA
# Current character & text mode
:alias current_byte_index vB
#: The current offset into the message.
:alias current_byte_value vC
#: The read value of the current byte.
:monitor current_byte_index "%i (decimal)"
:monitor current_byte_value "%c (ascii)"
:alias _msg_reg_0 msg_start_x :alias _msg_reg_end current_byte_value
# Todo: consider storing the decoded values in memory...
# useful if want to do layout.
# Universal control characters
:const CHAR_NULL 0x00 #: End of message
# "Block" boundaries for text to allow sparse text rendering
:const CHAR_SPACE 0x20 #: Boundary: start of early block
:const CHAR_SINGLEQUOTE 0x27 #: Boundary: end of early block
:const CHAR_A 0x41 #: Boundary: start of letters
:const CHAR_Z 0x5A #: Boundary: end of letters
#: ### Formatting control characters
:const CHAR_ESCAPE 0x5E #: The start of an escape sequence.
#: `^` in text is treated as an escape sequence opener.
#:
#: The following Control codes are supported:
:const CHAR_NEWLINE 0x0A #: '\n' in text, goes back to the
:const CHAR_B 0x42 #: Background control code
:const CHAR_F 0x46 #: Foreground control code
:const CHAR_D 0x44 #: "Restore defaults"
:macro _base10 NAME { :calc NAME { CALLS + 0x30 } }
_base10 CHAR_0
_base10 CHAR_1
_base10 CHAR_2
_base10 CHAR_3
_base10 CHAR_4
_base10 CHAR_5
_base10 CHAR_6
_base10 CHAR_7
_base10 CHAR_8
_base10 CHAR_9
:const STYLE_PLANE_0 CHAR_0
:const STYLE_PLANE_1 CHAR_1
:const STYLE_PLANE_2 CHAR_2
:const STYLE_PLANE_3 CHAR_3
# Character constants (check with `& 0x80`; 0b10000000 works too)
:const END_OF_STRING CHAR_NULL
# A coherent-ish block of chars values, '0' <= char <= 'Z'
:const MAINBLOCK_START CHAR_SINGLEQUOTE
:const MAINBLOCK_END CHAR_Z
:calc MAINBLOCK_SPAN { MAINBLOCK_END - MAINBLOCK_START }
: current_msg_state
#: A struct for persisting the current message state.
: _current_msg_position
0x00 # Msg start x
0x00 # Msg start Y
0x00 # current_byte_index
0x00 # current_byte_value
: _current_msg_position_end
# This has to be a label since we need to use a real
# memory address to persist the state between calls.
: restore-current-msg
#: Restore the current message pointer to i.
0xF0 0x00
: _current_msg_addr
0x00 0x00
return
:macro set-current-msg LABEL {
#: Set the current message to begin showing in a resumable way.
#:
#: Args:
#: LABEL : label
#: Which null-terminated message to set as active.
#:
#: Clobbers:
#: v0 - v1
#:
#: Returns : void
:unpack long LABEL # Store LABEL into v0, vN; long allows reading higher mem
i := long _current_msg_addr
save v0 - v1 # Uses rStart - rEnd form to avoid advancing
}
:macro peek-next-msg-byte vN {
#: Load the byte at current_byte_index in the current message to vN
#:
#: Args:
#: vN : vN
#: A register containing an offset into the message.
#: Clobbers:
#: i
#: Returns: u8
#: The value of the byte at offset vN from msg start.
:call restore-current-msg
i += current_byte_index
load vN - vN
}
:macro read-msg-byte vN { current_byte_index += 1 peek-next-msg-byte vN }
#: Read the next byte of the message, advancing the current byte index.
#: Args:
#: vN : vN
#: Where to read the current byte to.
#: Updates:
#: current_byte_index, i
#: Returns:
#: vN
:macro read-next-byte-as-color vN { read-msg-byte vN vN -= CHAR_0 }
#: Read the next byte of the message as a color, advancing the current byte index.
#: Args:
#: vN : vN
#: Where to read the color to.
#: Updates:
#: current_byte_index
#: Clobbers:
#: i
#: Returns:
#: vN
:unless TERMLIB_SHOW_MSG
:const TERMLIB_SHOW_MSG 1 # Mark this function as implemented
:macro show-msg START_X START_Y MSG_LABEL {
#: Set the draw cursor to the given X, Y and render a null-terminated message.
#:
#: Args:
#: START_X :
#: A X position to move the cursor to.
#: START_Y :
#: A Y position to move the cursor to.
#: MSG_LABEL :
#: A label-like token which points to a null-terminated message.
#:
#: Clobbers:
#: i, v0 - v3, vF
msg_start_x := START_X msg_start_y := START_Y
set-current-msg MSG_LABEL
:call _show-msg-render
}
: _show-msg-render
#: Render an entire null-terminated message.
#:
#: Args:
#: msg_start_x : vN
#: X position where messages should be shown on the screen
#: msg_start_y : vN
#: Y position where message should be shown on the screen.
#: Clobbers:
#: v0, current_byte_value, current_byte_index, vF
#: Updates:
#: draw_x, draw_y
# :breakpoint render
current_byte_index := 0
set-draw-coords-to msg_start_x msg_start_y
loop
peek-next-msg-byte current_byte_value
# Exit on end of message, no exceptions
while current_byte_value != END_OF_STRING
# :breakpoint decide
v0 := 0
if current_byte_value == CHAR_ESCAPE then v0 := 4 # instructions 2 long
if current_byte_value == CHAR_NEWLINE then v0 := 8 #
jump0 _byte_action_table
: _byte_action_table
:call render-visible-glyph jump _byte_action_table_after
:call handle-control jump _byte_action_table_after
:call handle-newline # jump _byte_action_table_after # Last jump redundant
: _byte_action_table_after
: _byte_loop_end
current_byte_index += 1
again
: _show-msg-render-end
return
:end
:include "default_font_stringmodes.8o"