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