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