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