1 #include "mf_rlefont.h"
2
3 /* Number of reserved codes before the dictionary entries. */
4 #define DICT_START 24
5
6 /* Special reference to mean "fill with zeros to the end of the glyph" */
7 #define REF_FILLZEROS 16
8
9 /* RLE codes */
10 #define RLE_CODEMASK 0xC0
11 #define RLE_VALMASK 0x3F
12 #define RLE_ZEROS 0x00
13 #define RLE_64ZEROS 0x40
14 #define RLE_ONES 0x80
15 #define RLE_SHADE 0xC0
16
17 /* Dictionary "fill entries" for encoding bits directly. */
18 #define DICT_START7BIT 4
19 #define DICT_START6BIT 132
20 #define DICT_START5BIT 196
21 #define DICT_START4BIT 228
22 #define DICT_START3BIT 244
23 #define DICT_START2BIT 252
24
25 /* Find a pointer to the glyph matching a given character by searching
26 * through the character ranges. If the character is not found, return
27 * pointer to the default glyph.
28 */
find_glyph(const struct mf_rlefont_s * font,uint16_t character)29 static const uint8_t *find_glyph(const struct mf_rlefont_s *font,
30 uint16_t character)
31 {
32 unsigned i, index;
33 const struct mf_rlefont_char_range_s *range;
34 for (i = 0; i < font->char_range_count; i++)
35 {
36 range = &font->char_ranges[i];
37 index = character - range->first_char;
38 if (character >= range->first_char && index < range->char_count)
39 {
40 uint16_t offset = pgm_read_word(range->glyph_offsets + index);
41 return &range->glyph_data[offset];
42 }
43 }
44
45 return 0;
46 }
47
48 /* Structure to keep track of coordinates of the next pixel to be written,
49 * and also the bounds of the character. */
50 struct renderstate_r
51 {
52 int16_t x_begin;
53 int16_t x_end;
54 int16_t x;
55 int16_t y;
56 int16_t y_end;
57 mf_pixel_callback_t callback;
58 void *state;
59 };
60
61 /* Call the callback to write one pixel to screen, and advance to next
62 * pixel position. */
write_pixels(struct renderstate_r * rstate,uint16_t count,uint8_t alpha)63 static void write_pixels(struct renderstate_r *rstate, uint16_t count,
64 uint8_t alpha)
65 {
66 uint8_t rowlen;
67
68 /* Write row-by-row if the run spans multiple rows. */
69 while (rstate->x + count >= rstate->x_end)
70 {
71 rowlen = rstate->x_end - rstate->x;
72 rstate->callback(rstate->x, rstate->y, rowlen, alpha, rstate->state);
73 count -= rowlen;
74 rstate->x = rstate->x_begin;
75 rstate->y++;
76 }
77
78 /* Write the remaining part */
79 if (count)
80 {
81 rstate->callback(rstate->x, rstate->y, count, alpha, rstate->state);
82 rstate->x += count;
83 }
84 }
85
86 /* Skip the given number of pixels (0 alpha) */
skip_pixels(struct renderstate_r * rstate,uint16_t count)87 static void skip_pixels(struct renderstate_r *rstate, uint16_t count)
88 {
89 rstate->x += count;
90 while (rstate->x >= rstate->x_end)
91 {
92 rstate->x -= rstate->x_end - rstate->x_begin;
93 rstate->y++;
94 }
95 }
96
97 /* Decode and write out a RLE-encoded dictionary entry. */
write_rle_dictentry(const struct mf_rlefont_s * font,struct renderstate_r * rstate,uint8_t index)98 static void write_rle_dictentry(const struct mf_rlefont_s *font,
99 struct renderstate_r *rstate,
100 uint8_t index)
101 {
102 uint16_t offset = pgm_read_word(font->dictionary_offsets + index);
103 uint16_t length = pgm_read_word(font->dictionary_offsets + index + 1) - offset;
104 uint16_t i;
105
106 for (i = 0; i < length; i++)
107 {
108 uint8_t code = pgm_read_byte(font->dictionary_data + offset + i);
109 if ((code & RLE_CODEMASK) == RLE_ZEROS)
110 {
111 skip_pixels(rstate, code & RLE_VALMASK);
112 }
113 else if ((code & RLE_CODEMASK) == RLE_64ZEROS)
114 {
115 skip_pixels(rstate, ((code & RLE_VALMASK) + 1) * 64);
116 }
117 else if ((code & RLE_CODEMASK) == RLE_ONES)
118 {
119 write_pixels(rstate, (code & RLE_VALMASK) + 1, 255);
120 }
121 else if ((code & RLE_CODEMASK) == RLE_SHADE)
122 {
123 uint8_t count, alpha;
124 count = ((code & RLE_VALMASK) >> 4) + 1;
125 alpha = ((code & RLE_VALMASK) & 0xF) * 0x11;
126 write_pixels(rstate, count, alpha);
127 }
128 }
129 }
130
131 /* Get bit count for the "fill entries" */
fillentry_bitcount(uint8_t index)132 static uint8_t fillentry_bitcount(uint8_t index)
133 {
134 if (index >= DICT_START2BIT)
135 return 2;
136 else if (index >= DICT_START3BIT)
137 return 3;
138 else if (index >= DICT_START4BIT)
139 return 4;
140 else if (index >= DICT_START5BIT)
141 return 5;
142 else if (index >= DICT_START6BIT)
143 return 6;
144 else
145 return 7;
146 }
147
148 /* Decode and write out a direct binary codeword */
write_bin_codeword(const struct mf_rlefont_s * font,struct renderstate_r * rstate,uint8_t code)149 static void write_bin_codeword(const struct mf_rlefont_s *font,
150 struct renderstate_r *rstate,
151 uint8_t code)
152 {
153 uint8_t bitcount = fillentry_bitcount(code);
154 uint8_t byte = code - DICT_START7BIT;
155 uint8_t runlen = 0;
156
157 while (bitcount--)
158 {
159 if (byte & 1)
160 {
161 runlen++;
162 }
163 else
164 {
165 if (runlen)
166 {
167 write_pixels(rstate, runlen, 255);
168 runlen = 0;
169 }
170
171 skip_pixels(rstate, 1);
172 }
173
174 byte >>= 1;
175 }
176
177 if (runlen)
178 write_pixels(rstate, runlen, 255);
179 }
180
181 /* Decode and write out a reference codeword */
write_ref_codeword(const struct mf_rlefont_s * font,struct renderstate_r * rstate,uint8_t code)182 static void write_ref_codeword(const struct mf_rlefont_s *font,
183 struct renderstate_r *rstate,
184 uint8_t code)
185 {
186 if (code == 0)
187 {
188 skip_pixels(rstate, 1);
189 }
190 else if (code <= 15)
191 {
192 write_pixels(rstate, 1, 0x11 * code);
193 }
194 else if (code == REF_FILLZEROS)
195 {
196 /* Fill with zeroes to end */
197 rstate->y = rstate->y_end;
198 }
199 else if (code < DICT_START)
200 {
201 /* Reserved */
202 }
203 else if (code < DICT_START + font->rle_entry_count)
204 {
205 write_rle_dictentry(font, rstate, code - DICT_START);
206 }
207 else
208 {
209 write_bin_codeword(font, rstate, code);
210 }
211 }
212
213 /* Decode and write out a reference encoded dictionary entry. */
write_ref_dictentry(const struct mf_rlefont_s * font,struct renderstate_r * rstate,uint8_t index)214 static void write_ref_dictentry(const struct mf_rlefont_s *font,
215 struct renderstate_r *rstate,
216 uint8_t index)
217 {
218 uint16_t offset = pgm_read_word(font->dictionary_offsets + index);
219 uint16_t length = pgm_read_word(font->dictionary_offsets + index + 1) - offset;
220 uint16_t i;
221
222 for (i = 0; i < length; i++)
223 {
224 uint8_t code = pgm_read_byte(font->dictionary_data + offset + i);
225 write_ref_codeword(font, rstate, code);
226 }
227 }
228
229 /* Decode and write out an arbitrary glyph codeword */
write_glyph_codeword(const struct mf_rlefont_s * font,struct renderstate_r * rstate,uint8_t code)230 static void write_glyph_codeword(const struct mf_rlefont_s *font,
231 struct renderstate_r *rstate,
232 uint8_t code)
233 {
234 if (code >= DICT_START + font->rle_entry_count &&
235 code < DICT_START + font->dict_entry_count)
236 {
237 write_ref_dictentry(font, rstate, code - DICT_START);
238 }
239 else
240 {
241 write_ref_codeword(font, rstate, code);
242 }
243 }
244
245
mf_rlefont_render_character(const struct mf_font_s * font,int16_t x0,int16_t y0,uint16_t character,mf_pixel_callback_t callback,void * state)246 uint8_t mf_rlefont_render_character(const struct mf_font_s *font,
247 int16_t x0, int16_t y0,
248 uint16_t character,
249 mf_pixel_callback_t callback,
250 void *state)
251 {
252 const uint8_t *p;
253 uint8_t width;
254
255 struct renderstate_r rstate;
256 rstate.x_begin = x0;
257 rstate.x_end = x0 + font->width;
258 rstate.x = x0;
259 rstate.y = y0;
260 rstate.y_end = y0 + font->height;
261 rstate.callback = callback;
262 rstate.state = state;
263
264 p = find_glyph((struct mf_rlefont_s*)font, character);
265 if (!p)
266 return 0;
267
268 width = pgm_read_byte(p++);
269 while (rstate.y < rstate.y_end)
270 {
271 write_glyph_codeword((struct mf_rlefont_s*)font, &rstate, pgm_read_byte(p++));
272 }
273
274 return width;
275 }
276
mf_rlefont_character_width(const struct mf_font_s * font,uint16_t character)277 uint8_t mf_rlefont_character_width(const struct mf_font_s *font,
278 uint16_t character)
279 {
280 const uint8_t *p;
281 p = find_glyph((struct mf_rlefont_s*)font, character);
282 if (!p)
283 return 0;
284
285 return pgm_read_byte(p);
286 }
287