Added backlight, reset, triangle and corner commands
[hackover2013-badge-firmware.git] / drivers / lcd / tft / drawing.c
1 /**************************************************************************/
2 /*!
3 @file drawing.c
4 @author K. Townsend (microBuilder.eu)
5
6 drawLine and drawCircle adapted from a tutorial by Leonard McMillan:
7 http://www.cs.unc.edu/~mcmillan/
8
9 drawString based on an example from Eran Duchan:
10 http://www.pavius.net/downloads/tools/53-the-dot-factory
11
12 @section LICENSE
13
14 Software License Agreement (BSD License)
15
16 Copyright (c) 2010, microBuilder SARL
17 All rights reserved.
18
19 Redistribution and use in source and binary forms, with or without
20 modification, are permitted provided that the following conditions are met:
21 1. Redistributions of source code must retain the above copyright
22 notice, this list of conditions and the following disclaimer.
23 2. Redistributions in binary form must reproduce the above copyright
24 notice, this list of conditions and the following disclaimer in the
25 documentation and/or other materials provided with the distribution.
26 3. Neither the name of the copyright holders nor the
27 names of its contributors may be used to endorse or promote products
28 derived from this software without specific prior written permission.
29
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
31 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
32 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
33 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
34 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
35 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
39 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 */
41 /**************************************************************************/
42 #include <string.h>
43
44 #include "drawing.h"
45
46 #ifdef CFG_SDCARD
47 #include "bmp.h"
48 #endif
49
50 /**************************************************************************/
51 /* */
52 /* ----------------------- Private Methods ------------------------------ */
53 /* */
54 /**************************************************************************/
55
56 /**************************************************************************/
57 /*!
58 @brief Draws a single bitmap character
59 */
60 /**************************************************************************/
61 void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const uint8_t *glyph, uint8_t glyphHeightPages, uint8_t glyphWidthBits)
62 {
63 uint16_t verticalPage, horizBit, currentY, currentX;
64 uint16_t indexIntoGlyph;
65
66 // set initial current y
67 currentY = yPixel;
68 currentX = xPixel;
69
70 // for each page of the glyph
71 for (verticalPage = glyphHeightPages; verticalPage > 0; --verticalPage)
72 {
73 // for each horizontol bit
74 for (horizBit = 0; horizBit < glyphWidthBits; ++horizBit)
75 {
76 // next byte
77 indexIntoGlyph = (glyphHeightPages * horizBit) + verticalPage - 1;
78
79 currentX = xPixel + (horizBit);
80 // send the data byte
81 if (glyph[indexIntoGlyph] & (0X80)) drawPixel(currentX, currentY, color);
82 if (glyph[indexIntoGlyph] & (0X40)) drawPixel(currentX, currentY - 1, color);
83 if (glyph[indexIntoGlyph] & (0X20)) drawPixel(currentX, currentY - 2, color);
84 if (glyph[indexIntoGlyph] & (0X10)) drawPixel(currentX, currentY - 3, color);
85 if (glyph[indexIntoGlyph] & (0X08)) drawPixel(currentX, currentY - 4, color);
86 if (glyph[indexIntoGlyph] & (0X04)) drawPixel(currentX, currentY - 5, color);
87 if (glyph[indexIntoGlyph] & (0X02)) drawPixel(currentX, currentY - 6, color);
88 if (glyph[indexIntoGlyph] & (0X01)) drawPixel(currentX, currentY - 7, color);
89 }
90 // next line of pages
91 currentY += 8;
92 }
93 }
94
95 #if defined CFG_TFTLCD_INCLUDESMALLFONTS & CFG_TFTLCD_INCLUDESMALLFONTS == 1
96 /**************************************************************************/
97 /*!
98 @brief Draws a single smallfont character
99 */
100 /**************************************************************************/
101 void drawCharSmall(uint16_t x, uint16_t y, uint16_t color, uint8_t c, struct FONT_DEF font)
102 {
103 uint8_t col, column[font.u8Width];
104
105 // Check if the requested character is available
106 if ((c >= font.u8FirstChar) && (c <= font.u8LastChar))
107 {
108 // Retrieve appropriate columns from font data
109 for (col = 0; col < font.u8Width; col++)
110 {
111 column[col] = font.au8FontTable[((c - 32) * font.u8Width) + col]; // Get first column of appropriate character
112 }
113 }
114 else
115 {
116 // Requested character is not available in this font ... send a space instead
117 for (col = 0; col < font.u8Width; col++)
118 {
119 column[col] = 0xFF; // Send solid space
120 }
121 }
122
123 // Render each column
124 uint16_t xoffset, yoffset;
125 for (xoffset = 0; xoffset < font.u8Width; xoffset++)
126 {
127 for (yoffset = 0; yoffset < (font.u8Height + 1); yoffset++)
128 {
129 uint8_t bit = 0x00;
130 bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left
131 bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white)
132 if (bit)
133 {
134 drawPixel(x + xoffset, y + yoffset, color);
135 }
136 }
137 }
138 }
139 #endif
140
141 /**************************************************************************/
142 /*!
143 @brief Helper method to accurately draw individual circle points
144 */
145 /**************************************************************************/
146 void drawCirclePoints(int cx, int cy, int x, int y, uint16_t color)
147 {
148 if (x == 0)
149 {
150 drawPixel(cx, cy + y, color);
151 drawPixel(cx, cy - y, color);
152 drawPixel(cx + y, cy, color);
153 drawPixel(cx - y, cy, color);
154 }
155 else if (x == y)
156 {
157 drawPixel(cx + x, cy + y, color);
158 drawPixel(cx - x, cy + y, color);
159 drawPixel(cx + x, cy - y, color);
160 drawPixel(cx - x, cy - y, color);
161 }
162 else if (x < y)
163 {
164 drawPixel(cx + x, cy + y, color);
165 drawPixel(cx - x, cy + y, color);
166 drawPixel(cx + x, cy - y, color);
167 drawPixel(cx - x, cy - y, color);
168 drawPixel(cx + y, cy + x, color);
169 drawPixel(cx - y, cy + x, color);
170 drawPixel(cx + y, cy - x, color);
171 drawPixel(cx - y, cy - x, color);
172 }
173 }
174
175 /**************************************************************************/
176 /* */
177 /* ----------------------- Public Methods ------------------------------- */
178 /* */
179 /**************************************************************************/
180
181 /**************************************************************************/
182 /*!
183 @brief Draws a single pixel at the specified location
184
185 @param[in] x
186 Horizontal position
187 @param[in] y
188 Vertical position
189 @param[in] color
190 Color used when drawing
191 */
192 /**************************************************************************/
193 void drawPixel(uint16_t x, uint16_t y, uint16_t color)
194 {
195 if ((x >= lcdGetWidth()) || (y >= lcdGetHeight()))
196 {
197 // Pixel out of range
198 return;
199 }
200
201 // Redirect to LCD
202 lcdDrawPixel(x, y, color);
203 }
204
205 /**************************************************************************/
206 /*!
207 @brief Fills the screen with the specified color
208
209 @param[in] color
210 Color used when drawing
211 */
212 /**************************************************************************/
213 void drawFill(uint16_t color)
214 {
215 lcdFillRGB(color);
216 }
217
218 /**************************************************************************/
219 /*!
220 @brief Draws a simple color test pattern
221 */
222 /**************************************************************************/
223 void drawTestPattern(void)
224 {
225 lcdTest();
226 }
227
228 #if defined CFG_TFTLCD_INCLUDESMALLFONTS & CFG_TFTLCD_INCLUDESMALLFONTS == 1
229 /**************************************************************************/
230 /*!
231 @brief Draws a string using a small font (6 of 8 pixels high).
232
233 @param[in] x
234 Starting x co-ordinate
235 @param[in] y
236 Starting y co-ordinate
237 @param[in] color
238 Color to use when rendering the font
239 @param[in] text
240 The string to render
241 @param[in] font
242 Pointer to the FONT_DEF to use when drawing the string
243
244 @section Example
245
246 @code
247
248 #include "drivers/lcd/fonts/smallfonts.h"
249
250 drawStringSmall(1, 210, COLOR_WHITE, "5x8 System (Max 40 Characters)", Font_System5x8);
251 drawStringSmall(1, 220, COLOR_WHITE, "7x8 System (Max 30 Characters)", Font_System7x8);
252
253 @endcode
254 */
255 /**************************************************************************/
256 void drawStringSmall(uint16_t x, uint16_t y, uint16_t color, char* text, struct FONT_DEF font)
257 {
258 uint8_t l;
259 for (l = 0; l < strlen(text); l++)
260 {
261 drawCharSmall(x + (l * (font.u8Width + 1)), y, color, text[l], font);
262 }
263 }
264 #endif
265
266 /**************************************************************************/
267 /*!
268 @brief Draws a string using the supplied font
269
270 @param[in] x
271 Starting x co-ordinate
272 @param[in] y
273 Starting y co-ordinate
274 @param[in] color
275 Color to use when rendering the font
276 @param[in] fontInfo
277 Pointer to the FONT_INFO to use when drawing the string
278 @param[in] str
279 The string to render
280
281 @section Example
282
283 @code
284
285 #include "drivers/lcd/tft/fonts/veramono9.h"
286
287 drawString(0, 90, COLOR_BLACK, &bitstreamVeraSansMono9ptFontInfo, "Vera Mono 9 (30 chars wide)");
288 drawString(0, 105, COLOR_BLACK, &bitstreamVeraSansMono9ptFontInfo, "123456789012345678901234567890");
289
290 @endcode
291 */
292 /**************************************************************************/
293 void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str)
294 {
295 uint16_t currentX, charWidth, characterToOutput;
296 const FONT_CHAR_INFO *charInfo;
297 uint16_t charOffset;
298
299 // set current x, y to that of requested
300 currentX = x;
301
302 // while not NULL
303 while (*str != '\0')
304 {
305 // get character to output
306 characterToOutput = *str;
307
308 // get char info
309 charInfo = fontInfo->charInfo;
310
311 // some fonts have character descriptors, some don't
312 if (charInfo != NULL)
313 {
314 // get correct char offset
315 charInfo += (characterToOutput - fontInfo->startChar);
316
317 // get width from char info
318 charWidth = charInfo->widthBits;
319
320 // get offset from char info
321 charOffset = charInfo->offset;
322 }
323 else
324 {
325 // if no char info, char width is always 5
326 charWidth = 5;
327
328 // char offset - assume 5 * letter offset
329 charOffset = (characterToOutput - fontInfo->startChar) * 5;
330 }
331
332 // Send individual characters
333 drawCharBitmap(currentX, y, color, &fontInfo->data[charOffset], fontInfo->heightPages, charWidth);
334
335 // next char X
336 currentX += charWidth + 1;
337
338 // next char
339 str++;
340 }
341 }
342
343 /**************************************************************************/
344 /*!
345 @brief Returns the width in pixels of a string when it is rendered
346
347 This method can be used to determine whether a string will fit
348 inside a specific area, or if it needs to be broken up into multiple
349 lines to be properly rendered on the screen.
350
351 This function only applied to bitmap fonts (which can have variable
352 widths). All smallfonts (if available) are fixed width and can
353 easily have their width calculated without costly functions like
354 this one.
355
356 @param[in] fontInfo
357 Pointer to the FONT_INFO for the font that will be used
358 @param[in] str
359 The string that will be rendered
360 */
361 /**************************************************************************/
362 uint16_t drawGetStringWidth(const FONT_INFO *fontInfo, char *str)
363 {
364 uint16_t width = 0;
365 uint32_t currChar;
366 uint32_t startChar = fontInfo->startChar;
367
368 // until termination
369 for (currChar = *str; currChar; currChar = *(++str))
370 {
371 // if char info exists for the font, use width from there
372 if (fontInfo->charInfo != NULL)
373 {
374 width += fontInfo->charInfo[currChar - startChar].widthBits + 1;
375 }
376 else
377 {
378 width += 5 + 1;
379 }
380 }
381
382 /* return the wdith */
383 return width;
384 }
385
386 /**************************************************************************/
387 /*!
388 @brief Draws a bresenham line
389
390 @param[in] x0
391 Starting x co-ordinate
392 @param[in] y0
393 Starting y co-ordinate
394 @param[in] x1
395 Ending x co-ordinate
396 @param[in] y1
397 Ending y co-ordinate
398 @param[in] color
399 Color used when drawing
400 */
401 /**************************************************************************/
402 void drawLine ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color )
403 {
404 drawLineDotted(x0, y0, x1, y1, 0, 1, color);
405 }
406
407 /**************************************************************************/
408 /*!
409 @brief Draws a bresenham line with a fixed pattern of empty
410 and solid pixels
411
412 Based on: http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html
413
414 @param[in] x0
415 Starting x co-ordinate
416 @param[in] y0
417 Starting y co-ordinate
418 @param[in] x1
419 Ending x co-ordinate
420 @param[in] y1
421 Ending y co-ordinate
422 @param[in] empty
423 The number of 'empty' pixels to render
424 @param[in] solid
425 The number of 'solid' pixels to render
426 @param[in] color
427 Color used when drawing
428 */
429 /**************************************************************************/
430 void drawLineDotted ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t empty, uint16_t solid, uint16_t color )
431 {
432 if (solid == 0)
433 {
434 return;
435 }
436
437 // If a negative y int was passed in it will overflow to 65K something
438 // Ugly, but drawCircleFilled() can pass in negative values so we need
439 // to check the values here
440 y0 = y0 > 65000 ? 0 : y0;
441 y1 = y1 > 65000 ? 0 : y1;
442
443 // Check if we can use the optimised horizontal line method
444 if ((y0 == y1) && (empty == 0))
445 {
446 lcdDrawHLine(x0, x1, y0, color);
447 return;
448 }
449
450 // Check if we can use the optimised vertical line method.
451 // This can make a huge difference in performance, but may
452 // not work properly on every LCD controller:
453 // ex.: drawCircleFilled(120, 160, 50, COLOR_RED);
454 // = 678834 cycles using lcdDrawVLine w/ILI9328 = 9.43mS @ 72MHz
455 // = 7546261 w/o lcdDrawVLine, setting each pixel = 104.8mS @ 72MHz
456 if ((x0 == x1) && (empty == 0))
457 {
458 // Warning: This may actually be slower than drawing individual pixels on
459 // short lines ... Set a minimum line size to use the 'optimised' method
460 // (which changes the screen orientation) ?
461 lcdDrawVLine(x0, y0, y1, color);
462 return;
463 }
464
465 // Draw non-horizontal or dotted line
466 int dy = y1 - y0;
467 int dx = x1 - x0;
468 int stepx, stepy;
469 int emptycount, solidcount;
470
471 if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
472 if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
473 dy <<= 1; // dy is now 2*dy
474 dx <<= 1; // dx is now 2*dx
475
476 emptycount = empty;
477 solidcount = solid;
478
479 drawPixel(x0, y0, color); // always start with solid pixels
480 solidcount--;
481 if (dx > dy)
482 {
483 int fraction = dy - (dx >> 1); // same as 2*dy - dx
484 while (x0 != x1)
485 {
486 if (fraction >= 0)
487 {
488 y0 += stepy;
489 fraction -= dx; // same as fraction -= 2*dx
490 }
491 x0 += stepx;
492 fraction += dy; // same as fraction -= 2*dy
493 if (empty == 0)
494 {
495 // always draw a pixel ... no dotted line requested
496 drawPixel(x0, y0, color);
497 }
498 else if (solidcount)
499 {
500 // Draw solid pxiel and decrement counter
501 drawPixel(x0, y0, color);
502 solidcount--;
503 }
504 else if(emptycount)
505 {
506 // Empty pixel ... don't draw anything an decrement counter
507 emptycount--;
508 }
509 else
510 {
511 // Reset counters and draw solid pixel
512 emptycount = empty;
513 solidcount = solid;
514 drawPixel(x0, y0, color);
515 solidcount--;
516 }
517 }
518 }
519 else
520 {
521 int fraction = dx - (dy >> 1);
522 while (y0 != y1)
523 {
524 if (fraction >= 0)
525 {
526 x0 += stepx;
527 fraction -= dy;
528 }
529 y0 += stepy;
530 fraction += dx;
531 if (empty == 0)
532 {
533 // always draw a pixel ... no dotted line requested
534 drawPixel(x0, y0, color);
535 }
536 if (solidcount)
537 {
538 // Draw solid pxiel and decrement counter
539 drawPixel(x0, y0, color);
540 solidcount--;
541 }
542 else if(emptycount)
543 {
544 // Empty pixel ... don't draw anything an decrement counter
545 emptycount--;
546 }
547 else
548 {
549 // Reset counters and draw solid pixel
550 emptycount = empty;
551 solidcount = solid;
552 drawPixel(x0, y0, color);
553 solidcount--;
554 }
555 }
556 }
557 }
558
559 /**************************************************************************/
560 /*!
561 @brief Draws a circle
562
563 Based on: http://www.cs.unc.edu/~mcmillan/comp136/Lecture7/circle.html
564
565 @param[in] xCenter
566 The horizontal center of the circle
567 @param[in] yCenter
568 The vertical center of the circle
569 @param[in] radius
570 The circle's radius in pixels
571 @param[in] color
572 Color used when drawing
573 */
574 /**************************************************************************/
575 void drawCircle (uint16_t xCenter, uint16_t yCenter, uint16_t radius, uint16_t color)
576 {
577 int x = 0;
578 int y = radius;
579 int p = (5 - radius*4)/4;
580
581 drawCirclePoints(xCenter, yCenter, x, y, color);
582 while (x < y)
583 {
584 x++;
585 if (p < 0)
586 {
587 p += 2*x+1;
588 }
589 else
590 {
591 y--;
592 p += 2*(x-y)+1;
593 }
594 drawCirclePoints(xCenter, yCenter, x, y, color);
595 }
596 }
597
598 /**************************************************************************/
599 /*!
600 @brief Draws a filled circle
601
602 @param[in] xCenter
603 The horizontal center of the circle
604 @param[in] yCenter
605 The vertical center of the circle
606 @param[in] radius
607 The circle's radius in pixels
608 @param[in] color
609 Color used when drawing
610 */
611 /**************************************************************************/
612 void drawCircleFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, uint16_t color)
613 {
614 int16_t f = 1 - radius;
615 int16_t ddF_x = 1;
616 int16_t ddF_y = -2 * radius;
617 int16_t x = 0;
618 int16_t y = radius;
619 int16_t xc_px, yc_my, xc_mx, xc_py, yc_mx, xc_my;
620 int16_t lcdWidth = lcdGetWidth();
621
622 if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter-radius, xCenter, (yCenter-radius) + (2*radius), color);
623
624 while (x<y)
625 {
626 if (f >= 0)
627 {
628 y--;
629 ddF_y += 2;
630 f += ddF_y;
631 }
632 x++;
633 ddF_x += 2;
634 f += ddF_x;
635
636 xc_px = xCenter+x;
637 xc_mx = xCenter-x;
638 xc_py = xCenter+y;
639 xc_my = xCenter-y;
640 yc_mx = yCenter-x;
641 yc_my = yCenter-y;
642
643 // Make sure X positions are not negative or too large or the pixels will
644 // overflow. Y overflow is handled in drawLine().
645 if ((xc_px < lcdWidth) && (xc_px >= 0)) drawLine(xc_px, yc_my, xc_px, yc_my + 2*y, color);
646 if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yc_my, xc_mx, yc_my + 2*y, color);
647 if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yc_mx, xc_py, yc_mx + 2*x, color);
648 if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yc_mx, xc_my, yc_mx + 2*x, color);
649 }
650 }
651
652 /**************************************************************************/
653 /*!
654 @brief Draws a filled rounded corner
655
656 @param[in] xCenter
657 The horizontal center of the circle
658 @param[in] yCenter
659 The vertical center of the circle
660 @param[in] radius
661 The circle's radius in pixels
662 @param[in] position
663 The position of the corner, which affects how it will
664 be rendered
665 @param[in] color
666 Color used when drawing
667 */
668 /**************************************************************************/
669 void drawCornerFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, drawCornerPosition_t position, uint16_t color)
670 {
671 int16_t f = 1 - radius;
672 int16_t ddF_x = 1;
673 int16_t ddF_y = -2 * radius;
674 int16_t x = 0;
675 int16_t y = radius;
676 int16_t xc_px, yc_my, xc_mx, xc_py, yc_mx, xc_my;
677 int16_t lcdWidth = lcdGetWidth();
678
679 switch (position)
680 {
681 case DRAW_CORNERPOSITION_TOPRIGHT:
682 case DRAW_CORNERPOSITION_TOPLEFT:
683 if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter-radius, xCenter, yCenter, color);
684 break;
685 case DRAW_CORNERPOSITION_BOTTOMRIGHT:
686 case DRAW_CORNERPOSITION_BOTTOMLEFT:
687 if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter, xCenter, (yCenter-radius) + (2*radius), color);
688 break;
689 }
690
691 while (x<y)
692 {
693 if (f >= 0)
694 {
695 y--;
696 ddF_y += 2;
697 f += ddF_y;
698 }
699 x++;
700 ddF_x += 2;
701 f += ddF_x;
702
703 xc_px = xCenter+x;
704 xc_mx = xCenter-x;
705 xc_py = xCenter+y;
706 xc_my = xCenter-y;
707 yc_mx = yCenter-x;
708 yc_my = yCenter-y;
709
710 switch (position)
711 {
712 case DRAW_CORNERPOSITION_TOPRIGHT:
713 if ((xc_px < lcdWidth) && (xc_px >= 0)) drawLine(xc_px, yc_my, xc_px, yCenter, color);
714 if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yc_mx, xc_py, yCenter, color);
715 break;
716 case DRAW_CORNERPOSITION_BOTTOMRIGHT:
717 if ((xc_px < lcdWidth) && (xc_px >= 0)) drawLine(xc_px, yCenter, xc_px, yc_my + 2*y, color);
718 if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yCenter, xc_py, yc_mx + 2*x, color);
719 break;
720 case DRAW_CORNERPOSITION_TOPLEFT:
721 if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yc_my, xc_mx, yCenter, color);
722 if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yc_mx, xc_my, yCenter, color);
723 break;
724 case DRAW_CORNERPOSITION_BOTTOMLEFT:
725 if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yCenter, xc_mx, yc_my + 2*y, color);
726 if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yCenter, xc_my, yc_mx + 2*x, color);
727 break;
728 }
729 }
730 }
731
732 /**************************************************************************/
733 /*!
734 @brief Draws a simple arrow of the specified width
735
736 @param[in] x
737 X co-ordinate of the smallest point of the arrow
738 @param[in] y
739 Y co-ordinate of the smallest point of the arrow
740 @param[in] size
741 Total width/height of the arrow in pixels
742 @param[in] direction
743 The direction that the arrow is pointing
744 @param[in] color
745 Color used when drawing
746 */
747 /**************************************************************************/
748 void drawArrow(uint16_t x, uint16_t y, uint16_t size, drawDirection_t direction, uint16_t color)
749 {
750 drawPixel(x, y, color);
751
752 if (size == 1)
753 {
754 return;
755 }
756
757 uint32_t i;
758 switch (direction)
759 {
760 case DRAW_DIRECTION_LEFT:
761 for (i = 1; i<size; i++)
762 {
763 drawLine(x+i, y-i, x+i, y+i, color);
764 }
765 break;
766 case DRAW_DIRECTION_RIGHT:
767 for (i = 1; i<size; i++)
768 {
769 drawLine(x-i, y-i, x-i, y+i, color);
770 }
771 break;
772 case DRAW_DIRECTION_UP:
773 for (i = 1; i<size; i++)
774 {
775 drawLine(x-i, y+i, x+i, y+i, color);
776 }
777 break;
778 case DRAW_DIRECTION_DOWN:
779 for (i = 1; i<size; i++)
780 {
781 drawLine(x-i, y-i, x+i, y-i, color);
782 }
783 break;
784 default:
785 break;
786 }
787 }
788
789 /**************************************************************************/
790 /*!
791 @brief Draws a simple (empty) rectangle
792
793 @param[in] x0
794 Starting x co-ordinate
795 @param[in] y0
796 Starting y co-ordinate
797 @param[in] x1
798 Ending x co-ordinate
799 @param[in] y1
800 Ending y co-ordinate
801 @param[in] color
802 Color used when drawing
803 */
804 /**************************************************************************/
805 void drawRectangle ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
806 {
807 uint16_t x, y;
808
809 if (y1 < y0)
810 {
811 // Switch y1 and y0
812 y = y1;
813 y1 = y0;
814 y0 = y;
815 }
816
817 if (x1 < x0)
818 {
819 // Switch x1 and x0
820 x = x1;
821 x1 = x0;
822 x0 = x;
823 }
824
825 drawLine (x0, y0, x1, y0, color);
826 drawLine (x1, y0, x1, y1, color);
827 drawLine (x1, y1, x0, y1, color);
828 drawLine (x0, y1, x0, y0, color);
829 }
830
831 /**************************************************************************/
832 /*!
833 @brief Draws a filled rectangle
834
835 @param[in] x0
836 Starting x co-ordinate
837 @param[in] y0
838 Starting y co-ordinate
839 @param[in] x1
840 Ending x co-ordinate
841 @param[in] y1
842 Ending y co-ordinate
843 @param[in] color
844 Color used when drawing
845 */
846 /**************************************************************************/
847 void drawRectangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
848 {
849 int height;
850 uint16_t x, y;
851
852 if (y1 < y0)
853 {
854 // Switch y1 and y0
855 y = y1;
856 y1 = y0;
857 y0 = y;
858 }
859
860 if (x1 < x0)
861 {
862 // Switch x1 and x0
863 x = x1;
864 x1 = x0;
865 x0 = x;
866 }
867
868 height = y1 - y0;
869 for (height = y0; y1 > height - 1; ++height)
870 {
871 drawLine(x0, height, x1, height, color);
872 }
873 }
874
875 /**************************************************************************/
876 /*!
877 @brief Draws a filled rectangle with rounded corners
878
879 @param[in] x0
880 Starting x co-ordinate
881 @param[in] y0
882 Starting y co-ordinate
883 @param[in] x1
884 Ending x co-ordinate
885 @param[in] y1
886 Ending y co-ordinate
887 @param[in] color
888 Color used when drawing
889 @param[in] radius
890 Corner radius in pixels
891 @param[in] corners
892 Which corners to round
893 */
894 /**************************************************************************/
895 void drawRectangleRounded ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color, uint16_t radius, drawRoundedCorners_t corners )
896 {
897 int height;
898 uint16_t y;
899
900 if (corners == DRAW_ROUNDEDCORNERS_NONE)
901 {
902 drawRectangleFilled(x0, y0, x1, y1, color);
903 return;
904 }
905
906 // Calculate height
907 if (y1 < y0)
908 {
909 y = y1;
910 y1 = y0;
911 y0 = y;
912 }
913 height = y1 - y0;
914
915 // Check radius
916 if (radius > height / 2)
917 {
918 radius = height / 2;
919 }
920 radius -= 1;
921
922 // Draw body
923 drawRectangleFilled(x0 + radius, y0, x1 - radius, y1, color);
924
925 switch (corners)
926 {
927 case DRAW_ROUNDEDCORNERS_ALL:
928 drawCircleFilled(x0 + radius, y0 + radius, radius, color);
929 drawCircleFilled(x1 - radius, y0 + radius, radius, color);
930 drawCircleFilled(x0 + radius, y1 - radius, radius, color);
931 drawCircleFilled(x1 - radius, y1 - radius, radius, color);
932 if (radius*2+1 < height)
933 {
934 drawRectangleFilled(x0, y0 + radius, x0 + radius, y1 - radius, color);
935 drawRectangleFilled(x1 - radius, y0 + radius, x1, y1 - radius, color);
936 }
937 break;
938 case DRAW_ROUNDEDCORNERS_TOP:
939 drawCircleFilled(x0 + radius, y0 + radius, radius, color);
940 drawCircleFilled(x1 - radius, y0 + radius, radius, color);
941 drawRectangleFilled(x0, y0 + radius, x0 + radius, y1, color);
942 drawRectangleFilled(x1 - radius, y0 + radius, x1, y1, color);
943 break;
944 case DRAW_ROUNDEDCORNERS_BOTTOM:
945 drawCircleFilled(x0 + radius, y1 - radius, radius, color);
946 drawCircleFilled(x1 - radius, y1 - radius, radius, color);
947 drawRectangleFilled(x0, y0, x0 + radius, y1 - radius, color);
948 drawRectangleFilled(x1 - radius, y0, x1, y1 - radius, color);
949 break;
950 case DRAW_ROUNDEDCORNERS_LEFT:
951 drawCircleFilled(x0 + radius, y0 + radius, radius, color);
952 drawCircleFilled(x0 + radius, y1 - radius, radius, color);
953 if (radius*2+1 < height)
954 {
955 drawRectangleFilled(x0, y0 + radius, x0 + radius, y1 - radius, color);
956 }
957 drawRectangleFilled(x1 - radius, y0, x1, y1, color);
958 break;
959 case DRAW_ROUNDEDCORNERS_RIGHT:
960 drawCircleFilled(x1 - radius, y0 + radius, radius, color);
961 drawCircleFilled(x1 - radius, y1 - radius, radius, color);
962 if (radius*2+1 < height)
963 {
964 drawRectangleFilled(x1 - radius, y0 + radius, x1, y1 - radius, color);
965 }
966 drawRectangleFilled(x0, y0, x0 + radius, y1, color);
967 break;
968 default:
969 break;
970 }
971 }
972
973 /**************************************************************************/
974 /*!
975 @brief Draws a triangle
976
977 @param[in] x0
978 x co-ordinate for point 0
979 @param[in] y0
980 y co-ordinate for point 0
981 @param[in] x1
982 x co-ordinate for point 1
983 @param[in] y1
984 y co-ordinate for point 1
985 @param[in] x2
986 x co-ordinate for point 2
987 @param[in] y2
988 y co-ordinate for point 2
989 @param[in] color
990 Color used when drawing
991 */
992 /**************************************************************************/
993 void drawTriangle ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
994 {
995 drawLine(x0, y0, x1, y1, color);
996 drawLine(x1, y1, x2, y2, color);
997 drawLine(x2, y2, x0, y0, color);
998 }
999
1000 /**************************************************************************/
1001 /*!
1002 @brief Draws a triangle
1003
1004 @param[in] x0
1005 x co-ordinate for point 0
1006 @param[in] y0
1007 y co-ordinate for point 0
1008 @param[in] x1
1009 x co-ordinate for point 1
1010 @param[in] y1
1011 y co-ordinate for point 1
1012 @param[in] x2
1013 x co-ordinate for point 2
1014 @param[in] y2
1015 y co-ordinate for point 2
1016 @param[in] color
1017 Fill color
1018
1019 @section Example
1020
1021 @code
1022
1023 // Draw a white triangle
1024 drawTriangleFilled ( 100, 10, 20, 120, 230, 290, COLOR_WHITE);
1025 // Draw black circles at each point of the triangle
1026 drawCircleFilled(100, 10, 2, COLOR_BLACK);
1027 drawCircleFilled(20, 120, 2, COLOR_BLACK);
1028 drawCircleFilled(230, 290, 2, COLOR_BLACK);
1029
1030 @endcode
1031 */
1032 /**************************************************************************/
1033 void drawTriangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color)
1034 {
1035 // ToDo: re-order vertices by ascending Y values (smallest first)
1036
1037 int32_t dx1, dx2, dx3; // Interpolation deltas
1038 int32_t sx1, sx2, sy; // Scanline co-ordinates
1039
1040 sx1=sx2=x0 * 1000; // Use fixed point math for x axis values
1041 sy=y0;
1042
1043 // Calculate interpolation deltas
1044 if (y1-y0 > 0) dx1=((x1-x0)*1000)/(y1-y0);
1045 else dx1=0;
1046 if (y2-y0 > 0) dx2=((x2-x0)*1000)/(y2-y0);
1047 else dx2=0;
1048 if (y2-y1 > 0) dx3=((x2-x1)*1000)/(y2-y1);
1049 else dx3=0;
1050
1051 // Render scanlines (horizontal lines are the fastest rendering method)
1052 if (dx1 > dx2)
1053 {
1054 for(; sy<=y1; sy++, sx1+=dx2, sx2+=dx1)
1055 {
1056 drawLine(sx1/1000, sy, sx2/1000, sy, color);
1057 }
1058 sx2 = x1*1000;
1059 sy = y1;
1060 for(; sy<=y2; sy++, sx1+=dx2, sx2+=dx3)
1061 {
1062 drawLine(sx1/1000, sy, sx2/1000, sy, color);
1063 }
1064 }
1065 else
1066 {
1067 for(; sy<=y1; sy++, sx1+=dx1, sx2+=dx2)
1068 {
1069 drawLine(sx1/1000, sy, sx2/1000, sy, color);
1070 }
1071 sx1 = x1*1000;
1072 sy = y1;
1073 for(; sy<=y2; sy++, sx1+=dx3, sx2+=dx2)
1074 {
1075 drawLine(sx1/1000, sy, sx2/1000, sy, color);
1076 }
1077 }
1078 }
1079
1080 /**************************************************************************/
1081 /*!
1082 @brief Converts a 24-bit RGB color to an equivalent 16-bit RGB565 value
1083
1084 @param[in] r
1085 8-bit red
1086 @param[in] g
1087 8-bit green
1088 @param[in] b
1089 8-bit blue
1090
1091 @section Example
1092
1093 @code
1094
1095 // Get 16-bit equivalent of 24-bit color
1096 uint16_t gray = drawRGB24toRGB565(0x33, 0x33, 0x33);
1097
1098 @endcode
1099 */
1100 /**************************************************************************/
1101 uint16_t drawRGB24toRGB565(uint8_t r, uint8_t g, uint8_t b)
1102 {
1103 return ((r / 8) << 11) | ((g / 4) << 5) | (b / 8);
1104 }
1105
1106 /**************************************************************************/
1107 /*!
1108 @brief Converts a 16-bit RGB565 color to a standard 32-bit BGRA32
1109 color (with alpha set to 0xFF)
1110
1111 @param[in] color
1112 16-bit rgb565 color
1113
1114 @section Example
1115
1116 @code
1117
1118 // First convert 24-bit color to RGB565
1119 uint16_t rgb565 = drawRGB24toRGB565(0xFF, 0x00, 0x00);
1120
1121 // Convert RGB565 color back to BGRA32
1122 uint32_t bgra32 = drawRGB565toBGRA32(rgb565);
1123
1124 // Display results
1125 printf("BGRA32: 0x%08X R: %u G: %u B: %u A: %u \r\n",
1126 bgra32,
1127 (bgra32 & 0x000000FF), // Blue
1128 (bgra32 & 0x0000FF00) >> 8, // Green
1129 (bgra32 & 0x00FF0000) >> 16, // Red
1130 (bgra32 & 0xFF000000) >> 24); // Alpha
1131
1132 @endcode
1133 */
1134 /**************************************************************************/
1135 uint32_t drawRGB565toBGRA32(uint16_t color)
1136 {
1137 uint32_t bits = (uint32_t)color;
1138 uint32_t blue = bits & 0x001F; // 5 bits blue
1139 uint32_t green = bits & 0x07E0; // 6 bits green
1140 uint32_t red = bits & 0xF800; // 5 bits red
1141
1142 // Return shifted bits with alpha set to 0xFF
1143 return (red << 8) | (green << 5) | (blue << 3) | 0xFF000000;
1144 }
1145
1146 /**************************************************************************/
1147 /*!
1148 @brief Reverses a 16-bit color from BGR to RGB
1149 */
1150 /**************************************************************************/
1151 uint16_t drawBGR2RGB(uint16_t color)
1152 {
1153 uint16_t r, g, b;
1154
1155 b = (color>>0) & 0x1f;
1156 g = (color>>5) & 0x3f;
1157 r = (color>>11) & 0x1f;
1158
1159 return( (b<<11) + (g<<5) + (r<<0) );
1160 }
1161
1162 /**************************************************************************/
1163 /*!
1164 @brief Draws a progress bar with rounded corners
1165
1166 @param[in] x
1167 Starting x location
1168 @param[in] y
1169 Starting y location
1170 @param[in] width
1171 Total width of the progress bar in pixels
1172 @param[in] height
1173 Total height of the progress bar in pixels
1174 @param[in] borderCorners
1175 The type of rounded corners to render with the progress bar border
1176 @param[in] progressCorners
1177 The type of rounded corners to render with the inner progress bar
1178 @param[in] borderColor
1179 16-bit color for the outer border
1180 @param[in] borderFillColor
1181 16-bit color for the interior of the outer border
1182 @param[in] progressBorderColor
1183 16-bit color for the progress bar's border
1184 @param[in] progressFillColor
1185 16-bit color for the inner bar's fill
1186 @param[in] progress
1187 Progress percentage (between 0 and 100)
1188
1189 @section Example
1190
1191 @code
1192 #include "drivers/lcd/tft/drawing.h"
1193
1194 // Draw a the progress bar (150x15 pixels large, starting at X:10, Y:195
1195 // with rounded corners on the top and showing 72% progress)
1196 drawProgressBar(10, 195, 150, 15, DRAW_ROUNDEDCORNERS_TOP, DRAW_ROUNDEDCORNERS_TOP, COLOR_DARKERGRAY, COLOR_DARKGRAY, COLOR_LIMEGREENDIM, COLOR_LIMEGREEN, 72 );
1197
1198 @endcode
1199 */
1200 /**************************************************************************/
1201 void drawProgressBar ( uint16_t x, uint16_t y, uint16_t width, uint16_t height, drawRoundedCorners_t borderCorners, drawRoundedCorners_t progressCorners, uint16_t borderColor, uint16_t borderFillColor, uint16_t progressBorderColor, uint16_t progressFillColor, uint8_t progress )
1202 {
1203 // Draw border with rounded corners
1204 drawRectangleRounded(x, y, x + width, y + height, borderColor, 5, borderCorners);
1205 drawRectangleRounded(x+1, y+1, x + width - 1, y + height - 1, borderFillColor, 5, borderCorners);
1206
1207 // Progress bar
1208 if (progress > 0 && progress <= 100)
1209 {
1210 // Calculate bar size
1211 uint16_t bw;
1212 bw = (width - 6); // bar at 100%
1213 if (progress != 100)
1214 {
1215 bw = (bw * progress) / 100;
1216 }
1217 drawRectangleRounded(x + 3, y + 3, bw + x + 3, y + height - 3, progressBorderColor, 5, progressCorners);
1218 drawRectangleRounded(x + 4, y + 4, bw + x + 3 - 1, y + height - 4, progressFillColor, 5, progressCorners);
1219 }
1220 }
1221
1222 /**************************************************************************/
1223 /*!
1224 @brief Draws a simple button
1225
1226 @param[in] x
1227 Starting x location
1228 @param[in] y
1229 Starting y location
1230 @param[in] width
1231 Total width of the button in pixels
1232 @param[in] height
1233 Total height of the button in pixels
1234 @param[in] fontInfo
1235 Pointer to the FONT_INFO used to render the button text
1236 @param[in] fontHeight
1237 The height in pixels of the font (used for centering)
1238 @param[in] borderclr
1239 The rgb565 border color
1240 @param[in] fillclr
1241 The rgb565 background color
1242 @param[in] fontclr
1243 The rgb565 font color
1244 @param[in] text
1245 The text to render on the button
1246
1247 @section Example
1248
1249 @code
1250
1251 #include "drivers/lcd/tft/drawing.h"
1252 #include "drivers/lcd/tft/fonts/dejavusansbold9.h"
1253
1254 // Draw two buttons using Vera Sans Bold 9
1255 drawButton(20, 195, 200, 35, &dejaVuSansBold9ptFontInfo, 7, COLOR_DARKERGRAY, COLOR_DARKERGRAY, COLOR_WHITE, "System Settings");
1256 drawButton(20, 235, 200, 35, &dejaVuSansBold9ptFontInfo, 7, COLOR_LIMEGREENDIM, COLOR_LIMEGREEN, COLOR_BLACK, "System Settings");
1257
1258 @endcode
1259 */
1260 /**************************************************************************/
1261 void drawButton(uint16_t x, uint16_t y, uint16_t width, uint16_t height, const FONT_INFO *fontInfo, uint16_t fontHeight, uint16_t borderclr, uint16_t fillclr, uint16_t fontclr, char* text)
1262 {
1263 // Border
1264 drawRectangleRounded(x, y, x + width, y + height, borderclr, 5, DRAW_ROUNDEDCORNERS_ALL);
1265 // Fill
1266 drawRectangleRounded(x+2, y+2, x+width-2, y+height-2, fillclr, 5, DRAW_ROUNDEDCORNERS_ALL);
1267
1268 // Render text
1269 if (text != NULL)
1270 {
1271 uint16_t textWidth = drawGetStringWidth(&*fontInfo, text);
1272 uint16_t xStart = x + (width / 2) - (textWidth / 2);
1273 uint16_t yStart = y + (height / 2) - (fontHeight / 2) + 1;
1274 drawString(xStart, yStart, fontclr, &*fontInfo, text);
1275 }
1276 }
1277
1278 /**************************************************************************/
1279 /*!
1280 @brief Renders a 16x16 monochrome icon using the supplied uint16_t
1281 array.
1282
1283 @param[in] x
1284 The horizontal location to start rendering from
1285 @param[in] x
1286 The vertical location to start rendering from
1287 @param[in] color
1288 The RGB565 color to use when rendering the icon
1289 @param[in] icon
1290 The uint16_t array containing the 16x16 image data
1291
1292 @section Example
1293
1294 @code
1295
1296 #include "drivers/lcd/tft/drawing.h"
1297 #include "drivers/lcd/icons16.h"
1298
1299 // Renders the info icon, which has two seperate parts ... the exterior
1300 // and a seperate interior mask if you want to fill the contents with a
1301 // different color
1302 drawIcon16(132, 202, COLOR_BLUE, icons16_info);
1303 drawIcon16(132, 202, COLOR_WHITE, icons16_info_interior);
1304
1305 @endcode
1306 */
1307 /**************************************************************************/
1308 void drawIcon16(uint16_t x, uint16_t y, uint16_t color, uint16_t icon[])
1309 {
1310 int i;
1311 for (i = 0; i<16; i++)
1312 {
1313 if (icon[i] & (0X8000)) drawPixel(x, y+i, color);
1314 if (icon[i] & (0X4000)) drawPixel(x+1, y+i, color);
1315 if (icon[i] & (0X2000)) drawPixel(x+2, y+i, color);
1316 if (icon[i] & (0X1000)) drawPixel(x+3, y+i, color);
1317 if (icon[i] & (0X0800)) drawPixel(x+4, y+i, color);
1318 if (icon[i] & (0X0400)) drawPixel(x+5, y+i, color);
1319 if (icon[i] & (0X0200)) drawPixel(x+6, y+i, color);
1320 if (icon[i] & (0X0100)) drawPixel(x+7, y+i, color);
1321 if (icon[i] & (0X0080)) drawPixel(x+8, y+i, color);
1322 if (icon[i] & (0x0040)) drawPixel(x+9, y+i, color);
1323 if (icon[i] & (0X0020)) drawPixel(x+10, y+i, color);
1324 if (icon[i] & (0X0010)) drawPixel(x+11, y+i, color);
1325 if (icon[i] & (0X0008)) drawPixel(x+12, y+i, color);
1326 if (icon[i] & (0X0004)) drawPixel(x+13, y+i, color);
1327 if (icon[i] & (0X0002)) drawPixel(x+14, y+i, color);
1328 if (icon[i] & (0X0001)) drawPixel(x+15, y+i, color);
1329 }
1330 }
1331
1332 #ifdef CFG_SDCARD
1333 /**************************************************************************/
1334 /*!
1335 @brief Loads a 24-bit Windows bitmap image from an SD card and
1336 renders it
1337
1338 @section Example
1339
1340 @code
1341
1342 #include "drivers/lcd/tft/drawing.h"
1343
1344 // Draw image.bmp (from the root folder) starting at pixel 0,0
1345 bmp_error_t error = drawBitmapImage(0, 0, "/image.bmp");
1346
1347 if (error)
1348 {
1349 switch (error)
1350 {
1351 case BMP_ERROR_SDINITFAIL:
1352 break;
1353 case BMP_ERROR_FILENOTFOUND:
1354 break;
1355 case BMP_ERROR_NOTABITMAP:
1356 // First two bytes of image not 'BM'
1357 break;
1358 case BMP_ERROR_INVALIDBITDEPTH:
1359 // Image is not 24-bits
1360 break;
1361 case BMP_ERROR_COMPRESSEDDATA:
1362 // Image contains compressed data
1363 break;
1364 case BMP_ERROR_INVALIDDIMENSIONS:
1365 // Width or Height is > LCD size
1366 break;
1367 case BMP_ERROR_PREMATUREEOF:
1368 // EOF unexpectedly reached in pixel data
1369 break;
1370 }
1371 }
1372
1373 @endcode
1374 */
1375 /**************************************************************************/
1376 bmp_error_t drawBitmapImage(uint16_t x, uint16_t y, char *filename)
1377 {
1378 return bmpDrawBitmap(x, y, filename);
1379 }
1380
1381 #endif
This page took 0.121343 seconds and 5 git commands to generate.