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