X-Git-Url: https://git.rohieb.name/hackover2013-badge-firmware.git/blobdiff_plain/81ccc776bec25bb48917f651cc8e3b81022cd118..47fcece4b1d35197c1d8057a737e7307bab77113:/drivers/displays/tft/drawing.c diff --git a/drivers/displays/tft/drawing.c b/drivers/displays/tft/drawing.c index b7da3a3..b8ad086 100644 --- a/drivers/displays/tft/drawing.c +++ b/drivers/displays/tft/drawing.c @@ -6,9 +6,6 @@ drawLine and drawCircle adapted from a tutorial by Leonard McMillan: http://www.cs.unc.edu/~mcmillan/ - drawString based on an example from Eran Duchan: - http://www.pavius.net/downloads/tools/53-the-dot-factory - @section LICENSE Software License Agreement (BSD License) @@ -43,10 +40,6 @@ #include "drawing.h" -#ifdef CFG_SDCARD - #include "bmp.h" -#endif - /**************************************************************************/ /* */ /* ----------------------- Private Methods ------------------------------ */ @@ -66,50 +59,6 @@ void drawSwap(uint32_t a, uint32_t b) b = t; } -/**************************************************************************/ -/*! - @brief Draws a single bitmap character -*/ -/**************************************************************************/ -void drawCharBitmap(const uint16_t xPixel, const uint16_t yPixel, uint16_t color, const char *glyph, uint8_t cols, uint8_t rows) -{ - uint16_t currentY, currentX, indexIntoGlyph; - uint16_t _row, _col, _colPages; - - // set initial current y - currentY = yPixel; - currentX = xPixel; - - // Figure out how many columns worth of data we have - if (cols % 8) - _colPages = cols / 8 + 1; - else - _colPages = cols / 8; - - for (_row = 0; _row < rows; _row++) - { - for (_col = 0; _col < _colPages; _col++) - { - if (_row == 0) - indexIntoGlyph = _col; - else - indexIntoGlyph = (_row * _colPages) + _col; - - currentY = yPixel + _row; - currentX = xPixel + (_col*8); - // send the data byte - if (glyph[indexIntoGlyph] & (0X80)) drawPixel(currentX, currentY, color); - if (glyph[indexIntoGlyph] & (0X40)) drawPixel(currentX+1, currentY, color); - if (glyph[indexIntoGlyph] & (0X20)) drawPixel(currentX+2, currentY, color); - if (glyph[indexIntoGlyph] & (0X10)) drawPixel(currentX+3, currentY, color); - if (glyph[indexIntoGlyph] & (0X08)) drawPixel(currentX+4, currentY, color); - if (glyph[indexIntoGlyph] & (0X04)) drawPixel(currentX+5, currentY, color); - if (glyph[indexIntoGlyph] & (0X02)) drawPixel(currentX+6, currentY, color); - if (glyph[indexIntoGlyph] & (0X01)) drawPixel(currentX+7, currentY, color); - } - } -} - #if defined CFG_TFTLCD_INCLUDESMALLFONTS & CFG_TFTLCD_INCLUDESMALLFONTS == 1 /**************************************************************************/ /*! @@ -146,7 +95,7 @@ void drawCharSmall(uint16_t x, uint16_t y, uint16_t color, uint8_t c, struct FON { uint8_t bit = 0x00; bit = (column[xoffset] << (8 - (yoffset + 1))); // Shift current row bit left - bit = (bit >> 7); // Shift current row but right (results in 0x01 for black, and 0x00 for white) + bit = (bit >> 7); // Shift current row bit right (results in 0x01 for black, and 0x00 for white) if (bit) { drawPixel(x + xoffset, y + yoffset, color); @@ -156,40 +105,6 @@ void drawCharSmall(uint16_t x, uint16_t y, uint16_t color, uint8_t c, struct FON } #endif -/**************************************************************************/ -/*! - @brief Helper method to accurately draw individual circle points -*/ -/**************************************************************************/ -void drawCirclePoints(int cx, int cy, int x, int y, uint16_t color) -{ - if (x == 0) - { - drawPixel(cx, cy + y, color); - drawPixel(cx, cy - y, color); - drawPixel(cx + y, cy, color); - drawPixel(cx - y, cy, color); - } - else if (x == y) - { - drawPixel(cx + x, cy + y, color); - drawPixel(cx - x, cy + y, color); - drawPixel(cx + x, cy - y, color); - drawPixel(cx - x, cy - y, color); - } - else if (x < y) - { - drawPixel(cx + x, cy + y, color); - drawPixel(cx - x, cy + y, color); - drawPixel(cx + x, cy - y, color); - drawPixel(cx - x, cy - y, color); - drawPixel(cx + y, cy + x, color); - drawPixel(cx - y, cy + x, color); - drawPixel(cx + y, cy - x, color); - drawPixel(cx - y, cy - x, color); - } -} - /**************************************************************************/ /* */ /* ----------------------- Public Methods ------------------------------- */ @@ -210,14 +125,10 @@ void drawCirclePoints(int cx, int cy, int x, int y, uint16_t color) /**************************************************************************/ void drawPixel(uint16_t x, uint16_t y, uint16_t color) { - if ((x >= lcdGetWidth()) || (y >= lcdGetHeight())) + if ((x < lcdGetWidth()) && (y < lcdGetHeight())) { - // Pixel out of range - return; + lcdDrawPixel(x, y, color); } - - // Redirect to LCD - lcdDrawPixel(x, y, color); } /**************************************************************************/ @@ -281,128 +192,6 @@ void drawStringSmall(uint16_t x, uint16_t y, uint16_t color, char* text, struct } #endif -/**************************************************************************/ -/*! - @brief Draws a string using the supplied font - - @param[in] x - Starting x co-ordinate - @param[in] y - Starting y co-ordinate - @param[in] color - Color to use when rendering the font - @param[in] fontInfo - Pointer to the FONT_INFO to use when drawing the string - @param[in] str - The string to render - - @section Example - - @code - - #include "drivers/displays/tft/fonts/dejavusans9.h" - - drawString(0, 90, COLOR_BLACK, &dejaVuSans9ptFontInfo, "DejaVu Sans 9"); - drawString(0, 105, COLOR_BLACK, &dejaVuSans9ptFontInfo, "123456789012345678901234567890"); - - @endcode -*/ -/**************************************************************************/ -void drawString(uint16_t x, uint16_t y, uint16_t color, const FONT_INFO *fontInfo, char *str) -{ - uint16_t currentX, charWidth, characterToOutput; - const FONT_CHAR_INFO *charInfo; - uint16_t charOffset; - - // set current x, y to that of requested - currentX = x; - - // while not NULL - while (*str != '\0') - { - // get character to output - characterToOutput = *str; - - // get char info - charInfo = fontInfo->charInfo; - - // some fonts have character descriptors, some don't - if (charInfo != NULL) - { - // get correct char offset - charInfo += (characterToOutput - fontInfo->startChar); - - // get width from char info - charWidth = charInfo->widthBits; - - // get offset from char info - charOffset = charInfo->offset; - } - else - { - // if no char info, char width is always 5 - charWidth = 5; - - // char offset - assume 5 * letter offset - charOffset = (characterToOutput - fontInfo->startChar) * 5; - } - - // Send individual characters - // We need to manually calculate width in pages since this is screwy with variable width fonts - //uint8_t heightPages = charWidth % 8 ? charWidth / 8 : charWidth / 8 + 1; - drawCharBitmap(currentX, y, color, (const char *)(&fontInfo->data[charOffset]), charWidth, fontInfo->height); - - // next char X - currentX += charWidth + 1; - - // next char - str++; - } -} - -/**************************************************************************/ -/*! - @brief Returns the width in pixels of a string when it is rendered - - This method can be used to determine whether a string will fit - inside a specific area, or if it needs to be broken up into multiple - lines to be properly rendered on the screen. - - This function only applied to bitmap fonts (which can have variable - widths). All smallfonts (if available) are fixed width and can - easily have their width calculated without costly functions like - this one. - - @param[in] fontInfo - Pointer to the FONT_INFO for the font that will be used - @param[in] str - The string that will be rendered -*/ -/**************************************************************************/ -uint16_t drawGetStringWidth(const FONT_INFO *fontInfo, char *str) -{ - uint16_t width = 0; - uint32_t currChar; - uint32_t startChar = fontInfo->startChar; - - // until termination - for (currChar = *str; currChar; currChar = *(++str)) - { - // if char info exists for the font, use width from there - if (fontInfo->charInfo != NULL) - { - width += fontInfo->charInfo[currChar - startChar].widthBits + 1; - } - else - { - width += 5 + 1; - } - } - - /* return the width */ - return width > 0 ? width - 1 : width; -} - /**************************************************************************/ /*! @brief Draws a bresenham line @@ -449,6 +238,11 @@ void drawLine ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t col /**************************************************************************/ void drawLineDotted ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t empty, uint16_t solid, uint16_t color ) { + lcdProperties_t properties; + + // Get the LCD properties (to check for HW acceleration in the driver) + properties = lcdGetProperties(); + if (solid == 0) { return; @@ -461,7 +255,7 @@ void drawLineDotted ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16 y1 = y1 > 65000 ? 0 : y1; // Check if we can use the optimised horizontal line method - if ((y0 == y1) && (empty == 0)) + if ((y0 == y1) && (empty == 0) && properties.fastHLine) { lcdDrawHLine(x0, x1, y0, color); return; @@ -470,7 +264,7 @@ void drawLineDotted ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16 // Check if we can use the optimised vertical line method. // This can make a huge difference in performance, but may // not work properly on every LCD controller: - if ((x0 == x1) && (empty == 0)) + if ((x0 == x1) && (empty == 0) && properties.fastVLine) { // Warning: This may actually be slower than drawing individual pixels on // short lines ... Set a minimum line size to use the 'optimised' method @@ -591,25 +385,11 @@ void drawLineDotted ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16 /**************************************************************************/ void drawCircle (uint16_t xCenter, uint16_t yCenter, uint16_t radius, uint16_t color) { - int x = 0; - int y = radius; - int p = (5 - radius*4)/4; - - drawCirclePoints(xCenter, yCenter, x, y, color); - while (x < y) - { - x++; - if (p < 0) - { - p += 2*x+1; - } - else - { - y--; - p += 2*(x-y)+1; - } - drawCirclePoints(xCenter, yCenter, x, y, color); - } + drawPixel(xCenter, yCenter+radius, color); + drawPixel(xCenter, yCenter-radius, color); + drawPixel(xCenter+radius, yCenter, color); + drawPixel(xCenter-radius, yCenter, color); + drawCorner(xCenter, yCenter, radius, DRAW_CORNERS_ALL, color); } /**************************************************************************/ @@ -666,6 +446,74 @@ void drawCircleFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, uint } } +/**************************************************************************/ +/*! + @brief Draws a single 1-pixel wide corner + + @note Code courtesy Adafruit's excellent GFX lib: + https://github.com/adafruit/Adafruit-GFX-Library + + @param[in] xCenter + The horizontal center of the circle + @param[in] yCenter + The vertical center of the circle + @param[in] corner + The drawCorners_t representing the corner(s) to draw + @param[in] color + Color used when drawing + + @section EXAMPLE + + @code + + // Draw a top-left corner with a 10 pixel radius, centered at 20, 20 + drawCorner(20, 20, 10, DRAW_CORNER_TOPLEFT, COLOR_GRAY_128); + + @endcode +*/ +/**************************************************************************/ +void drawCorner (uint16_t xCenter, uint16_t yCenter, uint16_t r, drawCorners_t corner, uint16_t color) +{ + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x= 0) + { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (corner & DRAW_CORNERS_BOTTOMRIGHT) + { + drawPixel(xCenter + x, yCenter + y, color); + drawPixel(xCenter + y, yCenter + x, color); + } + if (corner & DRAW_CORNERS_TOPRIGHT) + { + drawPixel(xCenter + x, yCenter - y, color); + drawPixel(xCenter + y, yCenter - x, color); + } + if (corner & DRAW_CORNERS_BOTTOMLEFT) + { + drawPixel(xCenter - y, yCenter + x, color); + drawPixel(xCenter - x, yCenter + y, color); + } + if (corner & DRAW_CORNERS_TOPLEFT) + { + drawPixel(xCenter - y, yCenter - x, color); + drawPixel(xCenter - x, yCenter - y, color); + } + } +} + /**************************************************************************/ /*! @brief Draws a filled rounded corner @@ -683,7 +531,7 @@ void drawCircleFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, uint Color used when drawing */ /**************************************************************************/ -void drawCornerFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, drawCornerPosition_t position, uint16_t color) +void drawCornerFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, drawCorners_t position, uint16_t color) { int16_t f = 1 - radius; int16_t ddF_x = 1; @@ -693,16 +541,14 @@ void drawCornerFilled (uint16_t xCenter, uint16_t yCenter, uint16_t radius, draw int16_t xc_px, yc_my, xc_mx, xc_py, yc_mx, xc_my; int16_t lcdWidth = lcdGetWidth(); - switch (position) + + if ((position & DRAW_CORNERS_TOPRIGHT) || (position & DRAW_CORNERS_TOPLEFT)) { - case DRAW_CORNERPOSITION_TOPRIGHT: - case DRAW_CORNERPOSITION_TOPLEFT: - if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter-radius, xCenter, yCenter, color); - break; - case DRAW_CORNERPOSITION_BOTTOMRIGHT: - case DRAW_CORNERPOSITION_BOTTOMLEFT: - if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter, xCenter, (yCenter-radius) + (2*radius), color); - break; + if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter-radius, xCenter, yCenter, color); + } + if ((position & DRAW_CORNERS_BOTTOMRIGHT) || (position & DRAW_CORNERS_BOTTOMLEFT)) + { + if (xCenter < lcdWidth) drawLine(xCenter, yCenter-radius < 0 ? 0 : yCenter, xCenter, (yCenter-radius) + (2*radius), color); } while (x= 0)) drawLine(xc_px, yc_my, xc_px, yCenter, color); if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yc_mx, xc_py, yCenter, color); - break; - case DRAW_CORNERPOSITION_BOTTOMRIGHT: + } + if (position & DRAW_CORNERS_BOTTOMRIGHT) + { if ((xc_px < lcdWidth) && (xc_px >= 0)) drawLine(xc_px, yCenter, xc_px, yc_my + 2*y, color); if ((xc_py < lcdWidth) && (xc_py >= 0)) drawLine(xc_py, yCenter, xc_py, yc_mx + 2*x, color); - break; - case DRAW_CORNERPOSITION_TOPLEFT: + } + if (position & DRAW_CORNERS_TOPLEFT) + { if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yc_my, xc_mx, yCenter, color); if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yc_mx, xc_my, yCenter, color); - break; - case DRAW_CORNERPOSITION_BOTTOMLEFT: + } + if (position & DRAW_CORNERS_BOTTOMLEFT) + { if ((xc_mx < lcdWidth) && (xc_mx >= 0)) drawLine(xc_mx, yCenter, xc_mx, yc_my + 2*y, color); if ((xc_my < lcdWidth) && (xc_my >= 0)) drawLine(xc_my, yCenter, xc_my, yc_mx + 2*x, color); - break; } } } @@ -889,6 +737,119 @@ void drawRectangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, u } } +/**************************************************************************/ +/*! + @brief Draws a rectangle with rounded corners + + @param[in] x0 + Starting x co-ordinate + @param[in] y0 + Starting y co-ordinate + @param[in] x1 + Ending x co-ordinate + @param[in] y1 + Ending y co-ordinate + @param[in] color + Color used when drawing + @param[in] radius + Corner radius in pixels + @param[in] corners + Which corners to round + + @section EXAMPLE + @code + + drawRoundedRectangle ( 10, 10, 200, 200, COLOR_BLACK, 10, DRAW_CORNERS_ALL ); + + @endcode + +*/ +/**************************************************************************/ +void drawRoundedRectangle ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color, uint16_t radius, drawCorners_t corners ) +{ + int height; + uint16_t y; + + if (corners == DRAW_CORNERS_NONE) + { + drawRectangle(x0, y0, x1, y1, color); + return; + } + + // Calculate height + if (y1 < y0) + { + y = y1; + y1 = y0; + y0 = y; + } + height = y1 - y0; + + // Check radius + if (radius > height / 2) + { + radius = height / 2; + } + radius -= 1; + + switch (corners) + { + case DRAW_CORNERS_ALL: + drawCorner(x0 + radius, y0 + radius, radius, DRAW_CORNERS_TOPLEFT, color); + drawCorner(x1 - radius, y0 + radius, radius, DRAW_CORNERS_TOPRIGHT, color); + drawCorner(x0 + radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMLEFT, color); + drawCorner(x1 - radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMRIGHT, color); + if (radius*2+1 < height) + { + drawLine(x0, y0+radius, x0, y1-radius, color); + drawLine(x1, y0+radius, x1, y1-radius, color); + } + drawLine(x0+radius, y0, x1-radius, y0, color); + drawLine(x0+radius, y1, x1-radius, y1, color); + break; + case DRAW_CORNERS_TOP: + drawCorner(x0 + radius, y0 + radius, radius, DRAW_CORNERS_TOPLEFT, color); + drawCorner(x1 - radius, y0 + radius, radius, DRAW_CORNERS_TOPRIGHT, color); + drawLine(x0, y0+radius, x0, y1, color); + drawLine(x0, y1, x1, y1, color); + drawLine(x1, y1, x1, y0+radius, color); + drawLine(x0+radius, y0, x1-radius, y0, color); + break; + case DRAW_CORNERS_BOTTOM: + drawCorner(x0 + radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMLEFT, color); + drawCorner(x1 - radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMRIGHT, color); + drawLine(x0, y0, x1, y0, color); + drawLine(x1, y0, x1, y1-radius, color ); + drawLine(x1-radius, y1, x0+radius, y1, color); + drawLine(x0, y1-radius, x0, y0, color); + break; + case DRAW_CORNERS_LEFT: + drawCorner(x0 + radius, y0 + radius, radius, DRAW_CORNERS_TOPLEFT, color); + drawCorner(x0 + radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMLEFT, color); + if (radius*2+1 < height) + { + drawLine(x0, y0+radius, x0, y1-radius, color); + } + drawLine(x1, y0, x1, y1, color); + drawLine(x0+radius, y0, x1, y0, color); + drawLine(x0+radius, y1, x1, y1, color); + break; + case DRAW_CORNERS_RIGHT: + drawCorner(x1 - radius, y0 + radius, radius, DRAW_CORNERS_TOPRIGHT, color); + drawCorner(x1 - radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMRIGHT, color); + if (radius*2+1 < height) + { + drawLine(x1, y0+radius, x1, y1-radius, color); + } + drawLine(x0, y0, x0, y1, color); + drawLine(x0, y0, x1-radius, y0, color); + drawLine(x0, y1, x1-radius, y1, color); + break; + default: + break; + } +} + /**************************************************************************/ /*! @brief Draws a filled rectangle with rounded corners @@ -909,12 +870,12 @@ void drawRectangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, u Which corners to round */ /**************************************************************************/ -void drawRectangleRounded ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color, uint16_t radius, drawRoundedCorners_t corners ) +void drawRoundedRectangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color, uint16_t radius, drawCorners_t corners ) { int height; uint16_t y; - if (corners == DRAW_ROUNDEDCORNERS_NONE) + if (corners == DRAW_CORNERS_NONE) { drawRectangleFilled(x0, y0, x1, y1, color); return; @@ -941,41 +902,41 @@ void drawRectangleRounded ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, switch (corners) { - case DRAW_ROUNDEDCORNERS_ALL: - drawCircleFilled(x0 + radius, y0 + radius, radius, color); - drawCircleFilled(x1 - radius, y0 + radius, radius, color); - drawCircleFilled(x0 + radius, y1 - radius, radius, color); - drawCircleFilled(x1 - radius, y1 - radius, radius, color); + case DRAW_CORNERS_ALL: + drawCornerFilled(x0 + radius, y0 + radius, radius, DRAW_CORNERS_TOPLEFT, color); + drawCornerFilled(x1 - radius, y0 + radius, radius, DRAW_CORNERS_TOPRIGHT, color); + drawCornerFilled(x0 + radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMLEFT, color); + drawCornerFilled(x1 - radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMRIGHT, color); if (radius*2+1 < height) { drawRectangleFilled(x0, y0 + radius, x0 + radius, y1 - radius, color); drawRectangleFilled(x1 - radius, y0 + radius, x1, y1 - radius, color); } break; - case DRAW_ROUNDEDCORNERS_TOP: - drawCircleFilled(x0 + radius, y0 + radius, radius, color); - drawCircleFilled(x1 - radius, y0 + radius, radius, color); + case DRAW_CORNERS_TOP: + drawCornerFilled(x0 + radius, y0 + radius, radius, DRAW_CORNERS_TOPLEFT, color); + drawCornerFilled(x1 - radius, y0 + radius, radius, DRAW_CORNERS_TOPRIGHT, color); drawRectangleFilled(x0, y0 + radius, x0 + radius, y1, color); drawRectangleFilled(x1 - radius, y0 + radius, x1, y1, color); break; - case DRAW_ROUNDEDCORNERS_BOTTOM: - drawCircleFilled(x0 + radius, y1 - radius, radius, color); - drawCircleFilled(x1 - radius, y1 - radius, radius, color); + case DRAW_CORNERS_BOTTOM: + drawCornerFilled(x0 + radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMLEFT, color); + drawCornerFilled(x1 - radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMRIGHT, color); drawRectangleFilled(x0, y0, x0 + radius, y1 - radius, color); drawRectangleFilled(x1 - radius, y0, x1, y1 - radius, color); break; - case DRAW_ROUNDEDCORNERS_LEFT: - drawCircleFilled(x0 + radius, y0 + radius, radius, color); - drawCircleFilled(x0 + radius, y1 - radius, radius, color); + case DRAW_CORNERS_LEFT: + drawCornerFilled(x0 + radius, y0 + radius, radius, DRAW_CORNERS_TOPLEFT, color); + drawCornerFilled(x0 + radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMLEFT, color); if (radius*2+1 < height) { drawRectangleFilled(x0, y0 + radius, x0 + radius, y1 - radius, color); } drawRectangleFilled(x1 - radius, y0, x1, y1, color); break; - case DRAW_ROUNDEDCORNERS_RIGHT: - drawCircleFilled(x1 - radius, y0 + radius, radius, color); - drawCircleFilled(x1 - radius, y1 - radius, radius, color); + case DRAW_CORNERS_RIGHT: + drawCornerFilled(x1 - radius, y0 + radius, radius, DRAW_CORNERS_TOPRIGHT, color); + drawCornerFilled(x1 - radius, y1 - radius, radius, DRAW_CORNERS_BOTTOMRIGHT, color); if (radius*2+1 < height) { drawRectangleFilled(x1 - radius, y0 + radius, x1, y1 - radius, color); @@ -987,6 +948,104 @@ void drawRectangleRounded ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, } } +/**************************************************************************/ +/*! + @brief Draws a gradient-filled rectangle + + @param[in] x0 + Starting x co-ordinate + @param[in] y0 + Starting y co-ordinate + @param[in] x1 + Ending x co-ordinate + @param[in] y1 + Ending y co-ordinate + @param[in] startColor + The color at the start of the gradient + @param[in] endColor + The color at the end of the gradient + + @section EXAMPLE + + @code + + #include "drivers/displays/tft/drawing.h" + #include "drivers/displays/tft/aafonts.h" + #include "drivers/displays/tft/aafonts/aa2/DejaVuSansCondensed14_AA2.h" + + // Draw a gradient-filled rectangle with anti-aliased text inside it + + uint16_t btnWidth, btnHeight, btnX, btnY; + uint16_t fntX, fntY; + + btnWidth = 200; + btnHeight = 20; + btnX = 10; + btnY = 30; + + lcdFillRGB(0xFFFF); + + drawRectangle(btnX-1, btnY-1, btnX+btnWidth+1, btnY+btnHeight+1, COLOR_GRAY_80); + drawGradient(btnX, btnY, btnX+btnWidth, btnY+btnHeight, COLOR_WHITE, COLOR_GRAY_128); + + // Center text vertically and horizontally + fntY = btnY + ((btnHeight - DejaVuSansCondensed14_AA2.fontHeight) / 2); + fntX = btnX + ((btnWidth - aafontsGetStringWidth(&DejaVuSansCondensed14_AA2, "Click to continue"))/2); + aafontsDrawString(fntX, fntY, COLORTABLE_AA2_BLACKONWHITE, &DejaVuSansCondensed14_AA2, "Click to continue"); + + @endcode +*/ +/**************************************************************************/ +void drawGradient ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t startColor, uint16_t endColor) +{ + int height; + uint16_t x, y; + uint8_t r, g, b; + int16_t rDelta, gDelta, bDelta; + + // Clear gradient steps, etc. + r = g = b = 0; + rDelta = gDelta = bDelta = 0; + + if (y1 < y0) + { + // Switch y1 and y0 + y = y1; + y1 = y0; + y0 = y; + } + + if (x1 < x0) + { + // Switch x1 and x0 + x = x1; + x1 = x0; + x0 = x; + } + + height = y1 - y0; + + // Calculate global r/g/b changes between start and end colors + rDelta = ((endColor >> 11) & 0x1F) - ((startColor >> 11) & 0x1F); + gDelta = ((endColor >> 5) & 0x3F) - ((startColor >> 5) & 0x3F); + bDelta = (endColor & 0x1F) - (startColor & 0x1F); + + // Calculate interpolation deltas to 2 decimal places (fixed point) + rDelta = (rDelta * 100) / height; + gDelta = (gDelta * 100) / height; + bDelta = (bDelta * 100) / height; + + // Draw individual lines + for (height = y0; y1 > height - 1; ++height) + { + // Calculate new rgb values based on: start color + (line number * interpolation delta) + r = ((startColor >> 11) & 0x1F) + ((rDelta * (height - y0)) / 100); + g = ((startColor >> 5) & 0x3F) + ((gDelta * (height - y0)) / 100); + b = (startColor & 0x1F) + ((bDelta * (height - y0)) / 100); + drawLine(x0, height, x1, height, ((r & 0x1F) << 11) | ((g & 0x3F) << 5) | (b & 0x1F)); + } +} + /**************************************************************************/ /*! @brief Draws a triangle @@ -1103,202 +1162,6 @@ void drawTriangleFilled ( uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, ui } } -/**************************************************************************/ -/*! - @brief Converts a 24-bit RGB color to an equivalent 16-bit RGB565 value - - @param[in] r - 8-bit red - @param[in] g - 8-bit green - @param[in] b - 8-bit blue - - @section Example - - @code - - // Get 16-bit equivalent of 24-bit color - uint16_t gray = drawRGB24toRGB565(0x33, 0x33, 0x33); - - @endcode -*/ -/**************************************************************************/ -uint16_t drawRGB24toRGB565(uint8_t r, uint8_t g, uint8_t b) -{ - return ((r / 8) << 11) | ((g / 4) << 5) | (b / 8); -} - -/**************************************************************************/ -/*! - @brief Converts a 16-bit RGB565 color to a standard 32-bit BGRA32 - color (with alpha set to 0xFF) - - @param[in] color - 16-bit rgb565 color - - @section Example - - @code - - // First convert 24-bit color to RGB565 - uint16_t rgb565 = drawRGB24toRGB565(0xFF, 0x00, 0x00); - - // Convert RGB565 color back to BGRA32 - uint32_t bgra32 = drawRGB565toBGRA32(rgb565); - - // Display results - printf("BGRA32: 0x%08X R: %u G: %u B: %u A: %u \r\n", - bgra32, - (bgra32 & 0x000000FF), // Blue - (bgra32 & 0x0000FF00) >> 8, // Green - (bgra32 & 0x00FF0000) >> 16, // Red - (bgra32 & 0xFF000000) >> 24); // Alpha - - @endcode -*/ -/**************************************************************************/ -uint32_t drawRGB565toBGRA32(uint16_t color) -{ - uint32_t bits = (uint32_t)color; - uint32_t blue = bits & 0x001F; // 5 bits blue - uint32_t green = bits & 0x07E0; // 6 bits green - uint32_t red = bits & 0xF800; // 5 bits red - - // Return shifted bits with alpha set to 0xFF - return (red << 8) | (green << 5) | (blue << 3) | 0xFF000000; -} - -/**************************************************************************/ -/*! - @brief Reverses a 16-bit color from BGR to RGB -*/ -/**************************************************************************/ -uint16_t drawBGR2RGB(uint16_t color) -{ - uint16_t r, g, b; - - b = (color>>0) & 0x1f; - g = (color>>5) & 0x3f; - r = (color>>11) & 0x1f; - - return( (b<<11) + (g<<5) + (r<<0) ); -} - -/**************************************************************************/ -/*! - @brief Draws a progress bar with rounded corners - - @param[in] x - Starting x location - @param[in] y - Starting y location - @param[in] width - Total width of the progress bar in pixels - @param[in] height - Total height of the progress bar in pixels - @param[in] borderCorners - The type of rounded corners to render with the progress bar border - @param[in] progressCorners - The type of rounded corners to render with the inner progress bar - @param[in] borderColor - 16-bit color for the outer border - @param[in] borderFillColor - 16-bit color for the interior of the outer border - @param[in] progressBorderColor - 16-bit color for the progress bar's border - @param[in] progressFillColor - 16-bit color for the inner bar's fill - @param[in] progress - Progress percentage (between 0 and 100) - - @section Example - - @code - #include "drivers/displays/tft/drawing.h" - - // Draw a the progress bar (150x15 pixels large, starting at X:10, Y:195 - // with rounded corners on the top and showing 72% progress) - drawProgressBar(10, 195, 150, 15, DRAW_ROUNDEDCORNERS_TOP, DRAW_ROUNDEDCORNERS_TOP, COLOR_DARKERGRAY, COLOR_DARKGRAY, COLOR_LIMEGREENDIM, COLOR_LIMEGREEN, 72 ); - - @endcode -*/ -/**************************************************************************/ -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 ) -{ - // Draw border with rounded corners - drawRectangleRounded(x, y, x + width, y + height, borderColor, 5, borderCorners); - drawRectangleRounded(x+1, y+1, x + width - 1, y + height - 1, borderFillColor, 5, borderCorners); - - // Progress bar - if (progress > 0 && progress <= 100) - { - // Calculate bar size - uint16_t bw; - bw = (width - 6); // bar at 100% - if (progress != 100) - { - bw = (bw * progress) / 100; - } - drawRectangleRounded(x + 3, y + 3, bw + x + 3, y + height - 3, progressBorderColor, 5, progressCorners); - drawRectangleRounded(x + 4, y + 4, bw + x + 3 - 1, y + height - 4, progressFillColor, 5, progressCorners); - } -} - -/**************************************************************************/ -/*! - @brief Draws a simple button - - @param[in] x - Starting x location - @param[in] y - Starting y location - @param[in] width - Total width of the button in pixels - @param[in] height - Total height of the button in pixels - @param[in] fontInfo - Pointer to the FONT_INFO used to render the button text - @param[in] borderclr - The rgb565 border color - @param[in] fillclr - The rgb565 background color - @param[in] fontclr - The rgb565 font color - @param[in] text - The text to render on the button - - @section Example - - @code - - #include "drivers/displays/tft/drawing.h" - #include "drivers/displays/tft/fonts/dejavusans9.h" - - // Draw two buttons using Vera Sans Bold 9 - drawButton(20, 195, 200, 35, &dejaVuSans9ptFontInfo, COLOR_GRAY_80, COLOR_GRAY_80, COLOR_WHITE, "System Settings"); - drawButton(20, 235, 200, 35, &dejaVuSans9ptFontInfo, COLOR_THEME_LIMEGREEN_DARKER, COLOR_THEME_LIMEGREEN_BASE, COLOR_BLACK, "System Settings"); - - @endcode -*/ -/**************************************************************************/ -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) -{ - // Border - drawRectangleRounded(x, y, x + width, y + height, borderclr, 5, DRAW_ROUNDEDCORNERS_ALL); - // Fill - drawRectangleRounded(x+2, y+2, x+width-2, y+height-2, fillclr, 5, DRAW_ROUNDEDCORNERS_ALL); - - // Render text - if (text != NULL) - { - uint16_t textWidth = drawGetStringWidth(&*fontInfo, text); - uint16_t xStart = x + (width / 2) - (textWidth / 2); - uint16_t yStart = y + (height / 2) - (fontInfo->height / 2) + 1; - drawString(xStart, yStart, fontclr, &*fontInfo, text); - } -} - /**************************************************************************/ /*! @brief Renders a 16x16 monochrome icon using the supplied uint16_t @@ -1352,54 +1215,3 @@ void drawIcon16(uint16_t x, uint16_t y, uint16_t color, uint16_t icon[]) if (icon[i] & (0X0001)) drawPixel(x+15, y+i, color); } } - -#ifdef CFG_SDCARD -/**************************************************************************/ -/*! - @brief Loads a 24-bit Windows bitmap image from an SD card and - renders it - - @section Example - - @code - - #include "drivers/displays/tft/drawing.h" - - // Draw image.bmp (from the root folder) starting at pixel 0,0 - bmp_error_t error = drawBitmapImage(0, 0, "/image.bmp"); - - if (error) - { - switch (error) - { - case BMP_ERROR_SDINITFAIL: - break; - case BMP_ERROR_FILENOTFOUND: - break; - case BMP_ERROR_NOTABITMAP: - // First two bytes of image not 'BM' - break; - case BMP_ERROR_INVALIDBITDEPTH: - // Image is not 24-bits - break; - case BMP_ERROR_COMPRESSEDDATA: - // Image contains compressed data - break; - case BMP_ERROR_INVALIDDIMENSIONS: - // Width or Height is > LCD size - break; - case BMP_ERROR_PREMATUREEOF: - // EOF unexpectedly reached in pixel data - break; - } - } - - @endcode -*/ -/**************************************************************************/ -bmp_error_t drawBitmapImage(uint16_t x, uint16_t y, char *filename) -{ - return bmpDrawBitmap(x, y, filename); -} - -#endif