components/u8g2/csrc/u8x8_8x8.c

changeset 0
88d965579617
equal deleted inserted replaced
-1:000000000000 0:88d965579617
1 /*
2
3 u8x8_8x8.c
4
5 font procedures, directly interfaces display procedures
6
7 Universal 8bit Graphics Library (https://github.com/olikraus/u8g2/)
8
9 Copyright (c) 2016, olikraus@gmail.com
10 All rights reserved.
11
12 Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14
15 * Redistributions of source code must retain the above copyright notice, this list
16 of conditions and the following disclaimer.
17
18 * Redistributions in binary form must reproduce the above copyright notice, this
19 list of conditions and the following disclaimer in the documentation and/or other
20 materials provided with the distribution.
21
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
24 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
34 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35
36 */
37
38 #include "u8x8.h"
39
40 #if defined(ESP8266)
41 uint8_t u8x8_pgm_read_esp(const uint8_t * addr)
42 {
43 uint32_t bytes;
44 bytes = *(uint32_t*)((uint32_t)addr & ~3);
45 return ((uint8_t*)&bytes)[(uint32_t)addr & 3];
46 }
47 #endif
48
49
50 void u8x8_SetFont(u8x8_t *u8x8, const uint8_t *font_8x8)
51 {
52 u8x8->font = font_8x8;
53 }
54
55 /*
56 Args:
57 u8x8: ptr to u8x8 structure
58 encoding: glyph for which the data is requested (must be between 0 and 255)
59 buf: pointer to 8 bytes
60 */
61 static void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset) U8X8_NOINLINE;
62 static void u8x8_get_glyph_data(u8x8_t *u8x8, uint8_t encoding, uint8_t *buf, uint8_t tile_offset)
63 {
64 uint8_t first, last, tiles, i;
65 uint16_t offset;
66 first = u8x8_pgm_read(u8x8->font+0);
67 last = u8x8_pgm_read(u8x8->font+1);
68 tiles = u8x8_pgm_read(u8x8->font+2); /* new 2019 format */
69 tiles *= u8x8_pgm_read(u8x8->font+3); /* new 2019 format */
70
71 /* get the glyph bitmap from the font */
72 if ( first <= encoding && encoding <= last )
73 {
74 offset = encoding;
75 offset -= first;
76 offset *= tiles; /* new 2019 format */
77 offset += tile_offset; /* new 2019 format */
78 offset *= 8;
79 offset +=4; /* changed from 2 to 4, new 2019 format */
80 for( i = 0; i < 8; i++ )
81 {
82 buf[i] = u8x8_pgm_read(u8x8->font+offset);
83 offset++;
84 }
85 }
86 else
87 {
88 for( i = 0; i < 8; i++ )
89 {
90 buf[i] = 0;
91 }
92 }
93
94 /* invert the bitmap if required */
95 if ( u8x8->is_font_inverse_mode )
96 {
97 for( i = 0; i < 8; i++ )
98 {
99 buf[i] ^= 255;
100 }
101 }
102
103 }
104
105 void u8x8_DrawGlyph(u8x8_t *u8x8, uint8_t x, uint8_t y, uint8_t encoding)
106 {
107 uint8_t th = u8x8_pgm_read(u8x8->font+2); /* new 2019 format */
108 uint8_t tv = u8x8_pgm_read(u8x8->font+3); /* new 2019 format */
109 uint8_t xx, tile;
110 uint8_t buf[8];
111 th += x;
112 tv += y;
113 tile = 0;
114 do
115 {
116 xx = x;
117 do
118 {
119 u8x8_get_glyph_data(u8x8, encoding, buf, tile);
120 u8x8_DrawTile(u8x8, xx, y, 1, buf);
121 tile++;
122 xx++;
123 } while( xx < th );
124 y++;
125 } while( y < tv );
126 }
127
128
129 /*
130 Source: http://graphics.stanford.edu/~seander/bithacks.html
131 Section: Interleave bits by Binary Magic Numbers
132 Original codes is here:
133 static const unsigned int B[] = {0x55555555, 0x33333333, 0x0F0F0F0F, 0x00FF00FF};
134 static const unsigned int S[] = {1, 2, 4, 8};
135
136 unsigned int x; // Interleave lower 16 bits of x and y, so the bits of x
137 unsigned int y; // are in the even positions and bits from y in the odd;
138 unsigned int z; // z gets the resulting 32-bit Morton Number.
139 // x and y must initially be less than 65536.
140
141 x = (x | (x << S[3])) & B[3];
142 x = (x | (x << S[2])) & B[2];
143 x = (x | (x << S[1])) & B[1];
144 x = (x | (x << S[0])) & B[0];
145
146 y = (y | (y << S[3])) & B[3];
147 y = (y | (y << S[2])) & B[2];
148 y = (y | (y << S[1])) & B[1];
149 y = (y | (y << S[0])) & B[0];
150
151 z = x | (y << 1);
152 */
153 uint16_t u8x8_upscale_byte(uint8_t x)
154 {
155 uint16_t y = x;
156 y |= (y << 4); // x = (x | (x << S[2])) & B[2];
157 y &= 0x0f0f;
158 y |= (y << 2); // x = (x | (x << S[1])) & B[1];
159 y &= 0x3333;
160 y |= (y << 1); // x = (x | (x << S[0])) & B[0];
161 y &= 0x5555;
162
163 y |= (y << 1); // z = x | (y << 1);
164 return y;
165 }
166
167 static void u8x8_upscale_buf(uint8_t *src, uint8_t *dest) U8X8_NOINLINE;
168 static void u8x8_upscale_buf(uint8_t *src, uint8_t *dest)
169 {
170 uint8_t i = 4;
171 do
172 {
173 *dest++ = *src;
174 *dest++ = *src++;
175 i--;
176 } while( i > 0 );
177 }
178
179 static void u8x8_draw_2x2_subglyph(u8x8_t *u8x8, uint8_t x, uint8_t y, uint8_t encoding, uint8_t tile)
180 {
181 uint8_t i;
182 uint16_t t;
183 uint8_t buf[8];
184 uint8_t buf1[8];
185 uint8_t buf2[8];
186 u8x8_get_glyph_data(u8x8, encoding, buf, tile);
187 for( i = 0; i < 8; i ++ )
188 {
189 t = u8x8_upscale_byte(buf[i]);
190 buf1[i] = t >> 8;
191 buf2[i] = t & 255;
192 }
193 u8x8_upscale_buf(buf2, buf);
194 u8x8_DrawTile(u8x8, x, y, 1, buf);
195
196 u8x8_upscale_buf(buf2+4, buf);
197 u8x8_DrawTile(u8x8, x+1, y, 1, buf);
198
199 u8x8_upscale_buf(buf1, buf);
200 u8x8_DrawTile(u8x8, x, y+1, 1, buf);
201
202 u8x8_upscale_buf(buf1+4, buf);
203 u8x8_DrawTile(u8x8, x+1, y+1, 1, buf);
204 }
205
206
207 void u8x8_Draw2x2Glyph(u8x8_t *u8x8, uint8_t x, uint8_t y, uint8_t encoding)
208 {
209 uint8_t th = u8x8_pgm_read(u8x8->font+2); /* new 2019 format */
210 uint8_t tv = u8x8_pgm_read(u8x8->font+3); /* new 2019 format */
211 uint8_t xx, tile;
212 th *= 2;
213 th += x;
214 tv *= 2;
215 tv += y;
216 tile = 0;
217 do
218 {
219 xx = x;
220 do
221 {
222 u8x8_draw_2x2_subglyph(u8x8, xx, y, encoding, tile);
223 tile++;
224 xx+=2;
225 } while( xx < th );
226 y+=2;
227 } while( y < tv );
228 }
229
230 /* https://github.com/olikraus/u8g2/issues/474 */
231 static void u8x8_draw_1x2_subglyph(u8x8_t *u8x8, uint8_t x, uint8_t y, uint8_t encoding, uint8_t tile)
232 {
233 uint8_t i;
234 uint16_t t;
235 uint8_t buf[8];
236 uint8_t buf1[8];
237 uint8_t buf2[8];
238 u8x8_get_glyph_data(u8x8, encoding, buf, tile);
239 for( i = 0; i < 8; i ++ )
240 {
241 t = u8x8_upscale_byte(buf[i]);
242 buf1[i] = t >> 8;
243 buf2[i] = t & 255;
244 }
245 u8x8_DrawTile(u8x8, x, y, 1, buf2);
246 u8x8_DrawTile(u8x8, x, y+1, 1, buf1);
247 }
248
249 void u8x8_Draw1x2Glyph(u8x8_t *u8x8, uint8_t x, uint8_t y, uint8_t encoding)
250 {
251 uint8_t th = u8x8_pgm_read(u8x8->font+2); /* new 2019 format */
252 uint8_t tv = u8x8_pgm_read(u8x8->font+3); /* new 2019 format */
253 uint8_t xx, tile;
254 th += x;
255 tv *= 2;
256 tv += y;
257 tile = 0;
258 do
259 {
260 xx = x;
261 do
262 {
263 u8x8_draw_1x2_subglyph(u8x8, xx, y, encoding, tile);
264 tile++;
265 xx++;
266 } while( xx < th );
267 y+=2;
268 } while( y < tv );
269 }
270
271 /*
272 source: https://en.wikipedia.org/wiki/UTF-8
273 Bits from to bytes Byte 1 Byte 2 Byte 3 Byte 4 Byte 5 Byte 6
274 7 U+0000 U+007F 1 0xxxxxxx
275 11 U+0080 U+07FF 2 110xxxxx 10xxxxxx
276 16 U+0800 U+FFFF 3 1110xxxx 10xxxxxx 10xxxxxx
277 21 U+10000 U+1FFFFF 4 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
278 26 U+200000 U+3FFFFFF 5 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
279 31 U+4000000 U+7FFFFFFF 6 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
280
281
282 */
283
284 /* reset the internal state machine */
285 void u8x8_utf8_init(u8x8_t *u8x8)
286 {
287 u8x8->utf8_state = 0; /* also reset during u8x8_SetupDefaults() */
288 }
289
290 uint16_t u8x8_ascii_next(U8X8_UNUSED u8x8_t *u8x8, uint8_t b)
291 {
292 if ( b == 0 || b == '\n' ) /* '\n' terminates the string to support the string list procedures */
293 return 0x0ffff; /* end of string detected*/
294 return b;
295 }
296
297 /*
298 pass a byte from an utf8 encoded string to the utf8 decoder state machine
299 returns
300 0x0fffe: no glyph, just continue
301 0x0ffff: end of string
302 anything else: The decoded encoding
303 */
304 uint16_t u8x8_utf8_next(u8x8_t *u8x8, uint8_t b)
305 {
306 if ( b == 0 || b == '\n' ) /* '\n' terminates the string to support the string list procedures */
307 return 0x0ffff; /* end of string detected, pending UTF8 is discarded */
308 if ( u8x8->utf8_state == 0 )
309 {
310 if ( b >= 0xfc ) /* 6 byte sequence */
311 {
312 u8x8->utf8_state = 5;
313 b &= 1;
314 }
315 else if ( b >= 0xf8 )
316 {
317 u8x8->utf8_state = 4;
318 b &= 3;
319 }
320 else if ( b >= 0xf0 )
321 {
322 u8x8->utf8_state = 3;
323 b &= 7;
324 }
325 else if ( b >= 0xe0 )
326 {
327 u8x8->utf8_state = 2;
328 b &= 15;
329 }
330 else if ( b >= 0xc0 )
331 {
332 u8x8->utf8_state = 1;
333 b &= 0x01f;
334 }
335 else
336 {
337 /* do nothing, just use the value as encoding */
338 return b;
339 }
340 u8x8->encoding = b;
341 return 0x0fffe;
342 }
343 else
344 {
345 u8x8->utf8_state--;
346 /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */
347 u8x8->encoding<<=6;
348 b &= 0x03f;
349 u8x8->encoding |= b;
350 if ( u8x8->utf8_state != 0 )
351 return 0x0fffe; /* nothing to do yet */
352 }
353 return u8x8->encoding;
354 }
355
356
357
358 static uint8_t u8x8_draw_string(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s) U8X8_NOINLINE;
359 static uint8_t u8x8_draw_string(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
360 {
361 uint16_t e;
362 uint8_t cnt = 0;
363 uint8_t th = u8x8_pgm_read(u8x8->font+2); /* new 2019 format */
364
365 u8x8_utf8_init(u8x8);
366 for(;;)
367 {
368 e = u8x8->next_cb(u8x8, (uint8_t)*s);
369 if ( e == 0x0ffff )
370 break;
371 s++;
372 if ( e != 0x0fffe )
373 {
374 u8x8_DrawGlyph(u8x8, x, y, e);
375 x+=th;
376 cnt++;
377 }
378 }
379 return cnt;
380 }
381
382
383 uint8_t u8x8_DrawString(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
384 {
385 u8x8->next_cb = u8x8_ascii_next;
386 return u8x8_draw_string(u8x8, x, y, s);
387 }
388
389 uint8_t u8x8_DrawUTF8(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
390 {
391 u8x8->next_cb = u8x8_utf8_next;
392 return u8x8_draw_string(u8x8, x, y, s);
393 }
394
395
396
397 static uint8_t u8x8_draw_2x2_string(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s) U8X8_NOINLINE;
398 static uint8_t u8x8_draw_2x2_string(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
399 {
400 uint16_t e;
401 uint8_t cnt = 0;
402 u8x8_utf8_init(u8x8);
403 for(;;)
404 {
405 e = u8x8->next_cb(u8x8, (uint8_t)*s);
406 if ( e == 0x0ffff )
407 break;
408 s++;
409 if ( e != 0x0fffe )
410 {
411 u8x8_Draw2x2Glyph(u8x8, x, y, e);
412 x+=2;
413 cnt++;
414 }
415 }
416 return cnt;
417 }
418
419
420 uint8_t u8x8_Draw2x2String(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
421 {
422 u8x8->next_cb = u8x8_ascii_next;
423 return u8x8_draw_2x2_string(u8x8, x, y, s);
424 }
425
426 uint8_t u8x8_Draw2x2UTF8(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
427 {
428 u8x8->next_cb = u8x8_utf8_next;
429 return u8x8_draw_2x2_string(u8x8, x, y, s);
430 }
431
432
433
434 static uint8_t u8x8_draw_1x2_string(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s) U8X8_NOINLINE;
435 static uint8_t u8x8_draw_1x2_string(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
436 {
437 uint16_t e;
438 uint8_t cnt = 0;
439 u8x8_utf8_init(u8x8);
440 for(;;)
441 {
442 e = u8x8->next_cb(u8x8, (uint8_t)*s);
443 if ( e == 0x0ffff )
444 break;
445 s++;
446 if ( e != 0x0fffe )
447 {
448 u8x8_Draw1x2Glyph(u8x8, x, y, e);
449 x++;
450 cnt++;
451 }
452 }
453 return cnt;
454 }
455
456
457 uint8_t u8x8_Draw1x2String(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
458 {
459 u8x8->next_cb = u8x8_ascii_next;
460 return u8x8_draw_1x2_string(u8x8, x, y, s);
461 }
462
463 uint8_t u8x8_Draw1x2UTF8(u8x8_t *u8x8, uint8_t x, uint8_t y, const char *s)
464 {
465 u8x8->next_cb = u8x8_utf8_next;
466 return u8x8_draw_1x2_string(u8x8, x, y, s);
467 }
468
469
470
471 uint8_t u8x8_GetUTF8Len(u8x8_t *u8x8, const char *s)
472 {
473 uint16_t e;
474 uint8_t cnt = 0;
475 u8x8_utf8_init(u8x8);
476 for(;;)
477 {
478 e = u8x8_utf8_next(u8x8, *s);
479 if ( e == 0x0ffff )
480 break;
481 s++;
482 if ( e != 0x0fffe )
483 cnt++;
484 }
485 return cnt;
486 }
487
488

mercurial