Tue, 17 Nov 2020 20:21:11 +0100
Attempt to normalize the 19x27 font
make all "main" characters 15px wide.
5 | 1 | /* mbed UniGraphic library - Graphics class |
2 | * Copyright (c) 2015 Giuliano Dianda | |
3 | * Released under the MIT License: http://mbed.org/license/mit | |
4 | * | |
5 | * Derived work of: | |
6 | * | |
7 | * mbed GraphicsDisplay Display Library Base Class | |
8 | * Copyright (c) 2007-2009 sford | |
9 | * Released under the MIT License: http://mbed.org/license/mit | |
10 | * | |
11 | * mbed library for 240*320 pixel display TFT based on ILI9341 LCD Controller | |
12 | * Copyright (c) 2013 Peter Drescher - DC2PD | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 | * THE SOFTWARE. | |
21 | */ | |
26 | 22 | |
5 | 23 | |
24 | #include "GraphicsDisplay.h" | |
26 | 25 | |
5 | 26 | #define SWAP(a, b) { a ^= b; b ^= a; a ^= b; } |
27 | GraphicsDisplay::GraphicsDisplay(const char *name):TextDisplay(name) { | |
28 | set_font((unsigned char*)Terminal6x8,32,127,true); | |
29 | // foreground(0xFFFF); | |
30 | // background(0x0000); | |
31 | char_x = 0; | |
32 | char_y = 0; | |
33 | oriented_width=0; | |
34 | oriented_height=0; | |
35 | fontzoomver=1; | |
36 | fontzoomhor=1; | |
37 | auto_up = true; | |
38 | } | |
26 | 39 | |
5 | 40 | void GraphicsDisplay::WindowMax (void) |
41 | { | |
42 | window (0, 0, oriented_width, oriented_height); | |
43 | } | |
44 | void GraphicsDisplay::set_width(int width) | |
45 | { | |
46 | oriented_width = width; | |
47 | } | |
48 | void GraphicsDisplay::set_height(int height) | |
49 | { | |
50 | oriented_height = height; | |
51 | } | |
52 | int GraphicsDisplay::width() | |
53 | { | |
54 | return oriented_width; | |
55 | } | |
56 | int GraphicsDisplay::height() | |
57 | { | |
58 | return oriented_height; | |
59 | } | |
60 | void GraphicsDisplay::circle(int x0, int y0, int r, unsigned short color) | |
61 | { | |
62 | int x = -r, y = 0, err = 2-2*r, e2; | |
63 | do { | |
64 | pixel(x0-x, y0+y,color); | |
65 | pixel(x0+x, y0+y,color); | |
66 | pixel(x0+x, y0-y,color); | |
67 | pixel(x0-x, y0-y,color); | |
68 | e2 = err; | |
69 | if (e2 <= y) { | |
70 | err += ++y*2+1; | |
71 | if (-x == y && e2 <= x) e2 = 0; | |
72 | } | |
73 | if (e2 > x) err += ++x*2+1; | |
74 | } while (x <= 0); | |
75 | if(auto_up) copy_to_lcd(); | |
76 | } | |
77 | void GraphicsDisplay::fillcircle(int x0, int y0, int r, unsigned short color) | |
78 | { | |
79 | bool old_auto_up=auto_up; | |
80 | if(auto_up) auto_up=false; | |
81 | int x = -r, y = 0, err = 2-2*r, e2; | |
82 | do { | |
83 | vline(x0-x, y0-y, y0+y, color); | |
84 | vline(x0+x, y0-y, y0+y, color); | |
85 | e2 = err; | |
86 | if (e2 <= y) { | |
87 | err += ++y*2+1; | |
88 | if (-x == y && e2 <= x) e2 = 0; | |
89 | } | |
90 | if (e2 > x) err += ++x*2+1; | |
91 | } while (x <= 0); | |
92 | if(old_auto_up) | |
93 | { | |
94 | auto_up=true; | |
95 | copy_to_lcd(); | |
96 | } | |
97 | } | |
98 | void GraphicsDisplay::hline(int x0, int x1, int y, unsigned short color) | |
99 | { | |
100 | int len = x1 - x0 + 1; | |
101 | window(x0,y,len,1); | |
102 | // for (int j=0; j<len; j++) window_pushpixel(color); | |
103 | window_pushpixel(color, len); | |
104 | if(auto_up) copy_to_lcd(); | |
105 | return; | |
106 | } | |
107 | void GraphicsDisplay::vline(int x, int y0, int y1, unsigned short color) | |
108 | { | |
109 | int len = y1 - y0 + 1; | |
110 | window(x,y0,1,len); | |
111 | // for (int y=0; y<len; y++) window_pushpixel(color); | |
112 | window_pushpixel(color, len); | |
113 | if(auto_up) copy_to_lcd(); | |
114 | return; | |
115 | } | |
116 | void GraphicsDisplay::line(int x0, int y0, int x1, int y1, unsigned short color) | |
117 | { | |
118 | //WindowMax(); | |
119 | int dx = 0, dy = 0; | |
120 | int dx_sym = 0, dy_sym = 0; | |
121 | int dx_x2 = 0, dy_x2 = 0; | |
122 | int di = 0; | |
123 | ||
124 | dx = x1-x0; | |
125 | dy = y1-y0; | |
126 | ||
127 | if (dx == 0) { /* vertical line */ | |
128 | if (y1 < y0) SWAP(y0,y1); | |
129 | vline(x0,y0,y1,color); | |
130 | return; | |
131 | } | |
132 | ||
133 | if (dx > 0) { | |
134 | dx_sym = 1; | |
135 | } else { | |
136 | dx_sym = -1; | |
137 | } | |
138 | if (dy == 0) { /* horizontal line */ | |
139 | if (x1 < x0) SWAP(x1,x0); | |
140 | hline(x0,x1,y0,color); | |
141 | return; | |
142 | } | |
143 | ||
144 | if (dy > 0) { | |
145 | dy_sym = 1; | |
146 | } else { | |
147 | dy_sym = -1; | |
148 | } | |
149 | ||
150 | dx = dx_sym*dx; | |
151 | dy = dy_sym*dy; | |
152 | ||
153 | dx_x2 = dx*2; | |
154 | dy_x2 = dy*2; | |
155 | ||
156 | if (dx >= dy) { | |
157 | di = dy_x2 - dx; | |
158 | while (x0 != x1) { | |
159 | ||
160 | pixel(x0, y0, color); | |
161 | x0 += dx_sym; | |
162 | if (di<0) { | |
163 | di += dy_x2; | |
164 | } else { | |
165 | di += dy_x2 - dx_x2; | |
166 | y0 += dy_sym; | |
167 | } | |
168 | } | |
169 | pixel(x0, y0, color); | |
170 | } else { | |
171 | di = dx_x2 - dy; | |
172 | while (y0 != y1) { | |
173 | pixel(x0, y0, color); | |
174 | y0 += dy_sym; | |
175 | if (di < 0) { | |
176 | di += dx_x2; | |
177 | } else { | |
178 | di += dx_x2 - dy_x2; | |
179 | x0 += dx_sym; | |
180 | } | |
181 | } | |
182 | pixel(x0, y0, color); | |
183 | } | |
184 | if(auto_up) copy_to_lcd(); | |
185 | return; | |
186 | } | |
187 | void GraphicsDisplay::rect(int x0, int y0, int x1, int y1, unsigned short color) | |
188 | { | |
189 | bool old_auto_up=auto_up; | |
190 | if(auto_up) auto_up=0; | |
191 | if (x1 > x0) hline(x0,x1,y0,color); | |
192 | else hline(x1,x0,y0,color); | |
193 | ||
194 | if (y1 > y0) vline(x0,y0,y1,color); | |
195 | else vline(x0,y1,y0,color); | |
196 | ||
197 | if (x1 > x0) hline(x0,x1,y1,color); | |
198 | else hline(x1,x0,y1,color); | |
199 | ||
200 | if (y1 > y0) vline(x1,y0,y1,color); | |
201 | else vline(x1,y1,y0,color); | |
202 | if(old_auto_up) | |
203 | { | |
204 | auto_up=true; | |
205 | copy_to_lcd(); | |
206 | } | |
207 | return; | |
208 | } | |
209 | void GraphicsDisplay::fillrect(int x0, int y0, int x1, int y1, unsigned short color) | |
210 | { | |
211 | if(x0 > x1) SWAP(x0,x1); | |
212 | if(y0 > y1) SWAP(y0,y1); | |
26 | 213 | |
5 | 214 | int h = y1 - y0 + 1; |
215 | int w = x1 - x0 + 1; | |
216 | unsigned int pixels = h * w; | |
217 | window(x0,y0,w,h); | |
218 | // for (unsigned int p=0; p<pixels; p++) window_pushpixel(color); | |
219 | window_pushpixel(color, pixels); | |
220 | if(auto_up) copy_to_lcd(); | |
221 | return; | |
222 | } | |
223 | void GraphicsDisplay::locate(int x, int y) | |
224 | { | |
225 | char_x = x; | |
226 | char_y = y; | |
227 | } | |
228 | int GraphicsDisplay::columns() | |
229 | { | |
230 | return oriented_width / fonthor; | |
231 | } | |
232 | int GraphicsDisplay::rows() | |
233 | { | |
234 | return oriented_height / fontvert; | |
235 | } | |
236 | void GraphicsDisplay::set_font(unsigned char* f, unsigned char firstascii, unsigned char lastascii, bool proportional) | |
237 | { | |
238 | font = f; | |
239 | // read font parameter from start of array | |
240 | //fontoffset = font[0]; // bytes / char | |
241 | fonthor = font[1]; // get hor size of font | |
242 | fontvert = font[2]; // get vert size of font | |
243 | //fontbpl = font[3]; // bytes per line | |
244 | fontbpl = (fontvert+7)>>3; //bytes per line, rounded up to multiple of 8 | |
245 | fontoffset = (fonthor*fontbpl)+1; | |
246 | firstch = firstascii; // first ascii code present in font array (usually 32) | |
247 | lastch = lastascii; // last ascii code present in font array (usually 127) | |
248 | fontprop = proportional; | |
249 | set_font_zoom(1,1); | |
250 | } | |
251 | void GraphicsDisplay::set_font_zoom(unsigned char x_mul, unsigned char y_mul) | |
252 | { | |
253 | fontzoomhor=((x_mul==0) ? 1:x_mul); | |
254 | fontzoomver=((y_mul==0) ? 1:y_mul); | |
255 | } | |
256 | int GraphicsDisplay::_putc(int value) | |
257 | { | |
258 | if (value == '\n') { // new line | |
259 | char_x = 0; | |
260 | char_y = char_y + fontvert*fontzoomver; | |
261 | if (char_y >= oriented_height - fontvert*fontzoomver) { | |
262 | char_y = 0; | |
263 | } | |
264 | } else { | |
265 | character(char_x, char_y, value); | |
266 | if(auto_up) copy_to_lcd(); | |
267 | } | |
268 | return value; | |
269 | } | |
45 | 270 | |
271 | void GraphicsDisplay::character(int c) | |
272 | { | |
273 | character(char_x, char_y, c); | |
274 | } | |
275 | ||
5 | 276 | void GraphicsDisplay::character(int x, int y, int c) |
277 | { | |
278 | char_x=x; | |
279 | char_y=y; | |
280 | int j,i,b; | |
281 | unsigned char* zeichen; | |
45 | 282 | unsigned char z,w,v, wtot; |
5 | 283 | |
284 | /* // read font parameter from start of array | |
285 | offset = font[0]; // bytes / char | |
286 | hor = font[1]; // get hor size of font | |
287 | vert = font[2]; // get vert size of font | |
288 | bpl = font[3]; // bytes per line | |
289 | */ | |
290 | if (char_x + fonthor*fontzoomhor > oriented_width) { | |
291 | char_x = 0; | |
292 | char_y = char_y + fontvert*fontzoomver; | |
293 | if (char_y > oriented_height - fontvert*fontzoomver) { | |
294 | char_y = 0; | |
295 | } | |
296 | } | |
297 | if ((c < firstch) || (c > lastch)) { // test char range - if not exist fill with blank | |
45 | 298 | window(char_x, char_y, fonthor*fontzoomhor, fontvert*fontzoomver); // char box |
5 | 299 | window_pushpixel(_background, fontzoomhor*fonthor*fontvert*fontzoomver); //(color, howmany) |
300 | w = fonthor; | |
301 | } else { | |
302 | zeichen = &font[((c-firstch) * fontoffset) + 4]; // start of char bitmap | |
303 | w = zeichen[0]; // width of actual char | |
45 | 304 | if((fontprop) && (w<fonthor)) |
305 | // put at least 1 blank after variable-width characters, except | |
306 | // characters that occupy whole fonthor space like "_" | |
307 | wtot = (w*fontzoomhor) + 1; | |
308 | else | |
309 | wtot = fonthor*fontzoomhor; | |
310 | window(char_x, char_y, wtot, fontvert*fontzoomver); // char box | |
311 | ||
5 | 312 | // construct the char into the buffer |
313 | for (j=0; j<(fontbpl); j++) { // vert bytes | |
45 | 314 | for (v=0; v<fontzoomver; v++) { // repeat horiz line for vertical zooming |
315 | for (int p=0; p<8; p++) { // pixel in the current vert byte | |
316 | if ((j*8+p) > fontvert) | |
317 | break; | |
318 | b = 1 << p; | |
319 | for (i=0; i<wtot; i++) { // horz line | |
320 | z = zeichen[(fontbpl * i) + j + 1]; | |
321 | window_pushpixel(( z & b ) ? _foreground : _background, fontzoomhor); //(color, howmany) | |
322 | } | |
323 | } | |
324 | } //for each zoomed vert | |
5 | 325 | } |
326 | } | |
45 | 327 | char_x += wtot; |
328 | } | |
329 | ||
330 | uint8_t GraphicsDisplay::char_width(char c, bool move_location) | |
331 | { | |
332 | unsigned char* zeichen; | |
333 | uint8_t w; | |
334 | ||
335 | zeichen = &font[((c-firstch) * fontoffset) + 4]; // start of char bitmap | |
336 | w = zeichen[0]; // width of actual char | |
337 | ||
5 | 338 | if((fontprop) && (w<fonthor)) |
45 | 339 | w = (w*fontzoomhor) + 1; |
5 | 340 | else |
45 | 341 | w = fonthor*fontzoomhor; |
342 | if (move_location) | |
343 | char_x += w; | |
344 | return w; | |
5 | 345 | } |
346 | ||
347 | void GraphicsDisplay::Bitmap_BW(Bitmap_s bm, int x, int y) | |
348 | { | |
349 | int h,v,b; | |
350 | // int cropX; | |
351 | char d; | |
352 | if(x<0) x=0; | |
353 | if(y<0) y=0; | |
354 | int cropX = (x+bm.xSize)-oriented_width; | |
26 | 355 | if(cropX<0) cropX=0; |
5 | 356 | window(x, y, bm.xSize-cropX, bm.ySize); |
357 | for(v=0; v < bm.ySize; v++) { // lines | |
358 | if((v + y) >= oriented_height) break; // no need to crop Y | |
359 | for(h=0; h < bm.xSize; h++) { // pixel | |
360 | if((h + x) >= oriented_width) break; | |
361 | d = bm.data[bm.Byte_in_Line * v + ((h & 0xF8) >> 3)]; | |
362 | b = 0x80 >> (h & 0x07); | |
363 | if((d & b) == 0) { | |
364 | window_pushpixel(_background); | |
365 | } else { | |
366 | window_pushpixel(_foreground); | |
367 | } | |
368 | } | |
369 | } | |
370 | if(auto_up) copy_to_lcd(); | |
371 | } | |
372 | void GraphicsDisplay::Bitmap(int x, int y, int w, int h,unsigned char *bitmap) | |
373 | { | |
374 | int j; | |
375 | unsigned char padd; | |
26 | 376 | unsigned short *bitmap_ptr = (unsigned short *)bitmap; |
5 | 377 | |
378 | padd = w%2; // the lines are padded to multiple of 4 bytes in a bitmap | |
379 | if(x<0) x=0; | |
380 | else if(x>=oriented_width) return; | |
381 | if(y<0) y=0; | |
382 | else if(y>=oriented_height) return; | |
383 | int cropX = (x+w)-oriented_width; | |
384 | if(cropX<0) cropX=0; | |
385 | int cropY = (y+h)-oriented_height; | |
386 | if(cropY<0) cropY=0; | |
387 | window(x, y, w-cropX, h-cropY); | |
388 | bitmap_ptr += ((h - 1)* (w + padd)); // begin of last line in array (first line of image)(standard bmp scan direction is left->right bottom->top) | |
389 | for (j = 0; j < h-cropY; j++) { //Lines | |
390 | window_pushpixelbuf(bitmap_ptr, w-cropX); | |
391 | bitmap_ptr -= w+padd; | |
392 | } | |
393 | if(auto_up) copy_to_lcd(); | |
394 | } | |
395 | ||
396 | // local filesystem is not implemented in kinetis board , but you can add a SD card | |
397 | // fixme this whole functions needs testing and speedup | |
398 | int GraphicsDisplay::BMP_16(int x, int y, const char *Name_BMP) | |
399 | { | |
400 | ||
401 | #define OffsetPixelWidth 18 | |
402 | #define OffsetPixelHeigh 22 | |
403 | #define OffsetFileSize 34 | |
404 | #define OffsetPixData 10 | |
405 | #define OffsetBPP 28 | |
406 | ||
407 | char filename[50]; | |
408 | unsigned char BMP_Header[54]; | |
409 | unsigned short BPP_t; | |
410 | unsigned int PixelWidth,PixelHeigh,start_data; | |
411 | unsigned int i,off; | |
412 | int padd,j; | |
413 | unsigned short *line; | |
414 | ||
415 | // get the filename | |
416 | i=0; | |
417 | while (*Name_BMP!='\0') { | |
418 | filename[i++]=*Name_BMP++; | |
419 | } | |
26 | 420 | filename[i] = 0; |
421 | ||
5 | 422 | FILE *Image = fopen((const char *)&filename[0], "rb"); // open the bmp file |
423 | if (!Image) { | |
424 | return(0); // error file not found ! | |
425 | } | |
426 | ||
427 | fread(&BMP_Header[0],1,54,Image); // get the BMP Header | |
428 | ||
429 | if (BMP_Header[0] != 0x42 || BMP_Header[1] != 0x4D) { // check magic byte | |
430 | fclose(Image); | |
431 | return(-1); // error no BMP file | |
432 | } | |
433 | ||
434 | BPP_t = BMP_Header[OffsetBPP] + (BMP_Header[OffsetBPP + 1] << 8); | |
435 | if (BPP_t != 0x0010) { | |
436 | fclose(Image); | |
437 | return(-2); // error no 16 bit BMP | |
438 | } | |
439 | ||
440 | PixelHeigh = BMP_Header[OffsetPixelHeigh] + (BMP_Header[OffsetPixelHeigh + 1] << 8) + (BMP_Header[OffsetPixelHeigh + 2] << 16) + (BMP_Header[OffsetPixelHeigh + 3] << 24); | |
441 | PixelWidth = BMP_Header[OffsetPixelWidth] + (BMP_Header[OffsetPixelWidth + 1] << 8) + (BMP_Header[OffsetPixelWidth + 2] << 16) + (BMP_Header[OffsetPixelWidth + 3] << 24); | |
442 | if (PixelHeigh > oriented_height + y || PixelWidth > oriented_width + x) { | |
443 | fclose(Image); | |
444 | return(-3); // to big | |
445 | } | |
446 | ||
447 | start_data = BMP_Header[OffsetPixData] + (BMP_Header[OffsetPixData + 1] << 8) + (BMP_Header[OffsetPixData + 2] << 16) + (BMP_Header[OffsetPixData + 3] << 24); | |
448 | ||
449 | line = (unsigned short *) malloc (2 * PixelWidth); // we need a buffer for a line | |
450 | if (line == NULL) { | |
451 | return(-4); // error no memory | |
452 | } | |
453 | ||
454 | // the bmp lines are padded to multiple of 4 bytes | |
455 | padd = -1; | |
456 | do { | |
457 | padd ++; | |
458 | } while ((PixelWidth * 2 + padd)%4 != 0); | |
459 | ||
460 | window(x, y,PixelWidth ,PixelHeigh); | |
461 | // wr_cmd(0x2C); // send pixel | |
462 | for (j = PixelHeigh - 1; j >= 0; j--) { //Lines bottom up | |
463 | off = j * (PixelWidth * 2 + padd) + start_data; // start of line | |
464 | fseek(Image, off ,SEEK_SET); | |
26 | 465 | fread(line,1,PixelWidth * 2,Image); // read a line - slow |
5 | 466 | /* for (i = 0; i < PixelWidth; i++) |
467 | { // copy pixel data to TFT | |
26 | 468 | // wr_16(line[i]); // one 16 bit pixel |
5 | 469 | window_pushpixel(line[i]); |
26 | 470 | |
5 | 471 | } */ |
472 | window_pushpixelbuf(line, PixelWidth); | |
473 | } | |
474 | free (line); | |
475 | fclose(Image); | |
476 | if(auto_up) copy_to_lcd(); | |
477 | return(1); | |
478 | } | |
479 | ||
480 | void GraphicsDisplay::cls (void) | |
481 | { | |
482 | unsigned int pixels = ( oriented_width * oriented_height); | |
483 | WindowMax(); | |
484 | for (unsigned int i = 0; i < pixels; i++) | |
485 | { | |
486 | window_pushpixel(_background); | |
487 | } | |
488 | } | |
489 | void GraphicsDisplay::set_auto_up(bool up) | |
490 | { | |
491 | if(up) auto_up = true; | |
492 | else auto_up = false; | |
493 | } | |
494 | bool GraphicsDisplay::get_auto_up(void) | |
495 | { | |
496 | return (auto_up); | |
497 | } |